diff options
author | Grant Limberg <glimberg@gmail.com> | 2015-04-25 18:59:52 -0700 |
---|---|---|
committer | Grant Limberg <glimberg@gmail.com> | 2015-04-25 18:59:52 -0700 |
commit | ec45aeb42aa644b71654b0467c4aebc80e896420 (patch) | |
tree | e7d544030dfc9e279007a8455a12206e895446eb | |
parent | a86a0ab2b13ae19d99f4667666a25b337e0b93f1 (diff) | |
parent | 7af1f3a79ab8928a3b49bac458ee87368c46edc5 (diff) | |
download | infinitytier-ec45aeb42aa644b71654b0467c4aebc80e896420.tar.gz infinitytier-ec45aeb42aa644b71654b0467c4aebc80e896420.zip |
Merge branch 'adamierymenko-dev' into android-jni
52 files changed, 11356 insertions, 2340 deletions
diff --git a/attic/Node.cpp b/attic/Node.cpp deleted file mode 100644 index 71c2d3fa..00000000 --- a/attic/Node.cpp +++ /dev/null @@ -1,949 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <sys/stat.h> - -#include <map> -#include <set> -#include <utility> -#include <algorithm> -#include <list> -#include <vector> -#include <string> - -#include "Constants.hpp" - -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <Windows.h> -#include <ShlObj.h> -#else -#include <fcntl.h> -#include <unistd.h> -#include <signal.h> -#include <sys/file.h> -#endif - -#include "../version.h" - -#include "Node.hpp" -#include "RuntimeEnvironment.hpp" -#include "Logger.hpp" -#include "Utils.hpp" -#include "Defaults.hpp" -#include "Identity.hpp" -#include "Topology.hpp" -#include "SocketManager.hpp" -#include "Packet.hpp" -#include "Switch.hpp" -#include "EthernetTap.hpp" -#include "CMWC4096.hpp" -#include "NodeConfig.hpp" -#include "Network.hpp" -#include "MulticastGroup.hpp" -#include "Multicaster.hpp" -#include "Mutex.hpp" -#include "SoftwareUpdater.hpp" -#include "Buffer.hpp" -#include "AntiRecursion.hpp" -#include "HttpClient.hpp" -#include "NetworkConfigMaster.hpp" - -namespace ZeroTier { - -struct _NodeImpl -{ - RuntimeEnvironment renv; - - std::string reasonForTerminationStr; - volatile Node::ReasonForTermination reasonForTermination; - - volatile bool started; - volatile bool running; - volatile bool resynchronize; - - volatile bool disableRootTopologyUpdates; - std::string overrideRootTopology; - - // This function performs final node tear-down - inline Node::ReasonForTermination terminate() - { - RuntimeEnvironment *RR = &renv; - LOG("terminating: %s",reasonForTerminationStr.c_str()); - - running = false; - - delete renv.updater; renv.updater = (SoftwareUpdater *)0; - delete renv.nc; renv.nc = (NodeConfig *)0; // shut down all networks, close taps, etc. - delete renv.topology; renv.topology = (Topology *)0; // now we no longer need routing info - delete renv.mc; renv.mc = (Multicaster *)0; - delete renv.antiRec; renv.antiRec = (AntiRecursion *)0; - delete renv.sw; renv.sw = (Switch *)0; // order matters less from here down - delete renv.http; renv.http = (HttpClient *)0; - delete renv.prng; renv.prng = (CMWC4096 *)0; - delete renv.log; renv.log = (Logger *)0; // but stop logging last of all - - return reasonForTermination; - } - - inline Node::ReasonForTermination terminateBecause(Node::ReasonForTermination r,const char *rstr) - { - reasonForTerminationStr = rstr; - reasonForTermination = r; - return terminate(); - } -}; - -Node::Node( - const char *hp, - EthernetTapFactory *tf, - SocketManager *sm, - NetworkConfigMaster *nm, - bool resetIdentity, - const char *overrideRootTopology) throw() : - _impl(new _NodeImpl) -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - - if ((hp)&&(hp[0])) - impl->renv.homePath = hp; - else impl->renv.homePath = ZT_DEFAULTS.defaultHomePath; - - impl->renv.tapFactory = tf; - impl->renv.sm = sm; - impl->renv.netconfMaster = nm; - - if (resetIdentity) { - // Forget identity and peer database, peer keys, etc. - Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); - Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); - Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "peers.persist").c_str()); - - // Truncate network config information in networks.d but leave the files since we - // still want to remember any networks we have joined. This will force those networks - // to be reconfigured with our newly regenerated identity after startup. - std::string networksDotD(impl->renv.homePath + ZT_PATH_SEPARATOR_S + "networks.d"); - std::map< std::string,bool > nwfiles(Utils::listDirectory(networksDotD.c_str())); - for(std::map<std::string,bool>::iterator nwf(nwfiles.begin());nwf!=nwfiles.end();++nwf) { - FILE *trun = fopen((networksDotD + ZT_PATH_SEPARATOR_S + nwf->first).c_str(),"w"); - if (trun) - fclose(trun); - } - } - - impl->reasonForTermination = Node::NODE_RUNNING; - impl->started = false; - impl->running = false; - impl->resynchronize = false; - - if (overrideRootTopology) { - impl->disableRootTopologyUpdates = true; - impl->overrideRootTopology = overrideRootTopology; - } else { - impl->disableRootTopologyUpdates = false; - } -} - -Node::~Node() -{ - delete (_NodeImpl *)_impl; -} - -static void _CBztTraffic(const SharedPtr<Socket> &fromSock,void *arg,const InetAddress &from,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &data) -{ - ((const RuntimeEnvironment *)arg)->sw->onRemotePacket(fromSock,from,data); -} - -static void _cbHandleGetRootTopology(void *arg,int code,const std::string &url,const std::string &body) -{ - RuntimeEnvironment *RR = (RuntimeEnvironment *)arg; - - if ((code != 200)||(body.length() == 0)) { - TRACE("failed to retrieve %s",url.c_str()); - return; - } - - try { - Dictionary rt(body); - if (!Topology::authenticateRootTopology(rt)) { - LOG("discarded invalid root topology update from %s (signature check failed)",url.c_str()); - return; - } - - { - std::string rootTopologyPath(RR->homePath + ZT_PATH_SEPARATOR_S + "root-topology"); - std::string rootTopology; - if (Utils::readFile(rootTopologyPath.c_str(),rootTopology)) { - Dictionary alreadyHave(rootTopology); - if (alreadyHave == rt) { - TRACE("retrieved root topology from %s but no change (same as on disk)",url.c_str()); - return; - } else if (alreadyHave.signatureTimestamp() > rt.signatureTimestamp()) { - TRACE("retrieved root topology from %s but no change (ours is newer)",url.c_str()); - return; - } - } - Utils::writeFile(rootTopologyPath.c_str(),body); - } - - RR->topology->setSupernodes(Dictionary(rt.get("supernodes"))); - } catch ( ... ) { - LOG("discarded invalid root topology update from %s (format invalid)",url.c_str()); - return; - } -} - -Node::ReasonForTermination Node::run() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - - impl->started = true; - impl->running = true; - - try { -#ifdef ZT_LOG_STDOUT - RR->log = new Logger((const char *)0,(const char *)0,0); -#else - RR->log = new Logger((RR->homePath + ZT_PATH_SEPARATOR_S + "node.log").c_str(),(const char *)0,131072); -#endif - - LOG("starting version %s",versionString()); - - // Create non-crypto PRNG right away in case other code in init wants to use it - RR->prng = new CMWC4096(); - - // Read identity public and secret, generating if not present - { - bool gotId = false; - std::string identitySecretPath(RR->homePath + ZT_PATH_SEPARATOR_S + "identity.secret"); - std::string identityPublicPath(RR->homePath + ZT_PATH_SEPARATOR_S + "identity.public"); - std::string idser; - if (Utils::readFile(identitySecretPath.c_str(),idser)) - gotId = RR->identity.fromString(idser); - if ((gotId)&&(!RR->identity.locallyValidate())) - gotId = false; - if (gotId) { - // Make sure identity.public matches identity.secret - idser = std::string(); - Utils::readFile(identityPublicPath.c_str(),idser); - std::string pubid(RR->identity.toString(false)); - if (idser != pubid) { - if (!Utils::writeFile(identityPublicPath.c_str(),pubid)) - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.public (home path not writable?)"); - } - } else { - LOG("no identity found or identity invalid, generating one... this might take a few seconds..."); - RR->identity.generate(); - LOG("generated new identity: %s",RR->identity.address().toString().c_str()); - idser = RR->identity.toString(true); - if (!Utils::writeFile(identitySecretPath.c_str(),idser)) - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.secret (home path not writable?)"); - idser = RR->identity.toString(false); - if (!Utils::writeFile(identityPublicPath.c_str(),idser)) - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.public (home path not writable?)"); - } - Utils::lockDownFile(identitySecretPath.c_str(),false); - } - - // Make sure networks.d exists (used by NodeConfig to remember networks) - { - std::string networksDotD(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d"); -#ifdef __WINDOWS__ - CreateDirectoryA(networksDotD.c_str(),NULL); -#else - mkdir(networksDotD.c_str(),0700); -#endif - } - // Make sure iddb.d exists (used by Topology to remember identities) - { - std::string iddbDotD(RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d"); -#ifdef __WINDOWS__ - CreateDirectoryA(iddbDotD.c_str(),NULL); -#else - mkdir(iddbDotD.c_str(),0700); -#endif - } - - RR->http = new HttpClient(); - RR->sw = new Switch(RR); - RR->mc = new Multicaster(RR); - RR->antiRec = new AntiRecursion(); - RR->topology = new Topology(RR); - try { - RR->nc = new NodeConfig(RR); - } catch (std::exception &exc) { - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unable to initialize IPC socket: is ZeroTier One already running?"); - } - RR->node = this; - -#ifdef ZT_AUTO_UPDATE - if (ZT_DEFAULTS.updateLatestNfoURL.length()) { - RR->updater = new SoftwareUpdater(RR); - RR->updater->cleanOldUpdates(); // clean out updates.d on startup - } else { - LOG("WARNING: unable to enable software updates: latest .nfo URL from ZT_DEFAULTS is empty (does this platform actually support software updates?)"); - } -#endif - - // Initialize root topology from defaults or root-toplogy file in home path on disk - if (impl->overrideRootTopology.length() == 0) { - std::string rootTopologyPath(RR->homePath + ZT_PATH_SEPARATOR_S + "root-topology"); - std::string rootTopology; - if (!Utils::readFile(rootTopologyPath.c_str(),rootTopology)) - rootTopology = ZT_DEFAULTS.defaultRootTopology; - try { - Dictionary rt(rootTopology); - - if (Topology::authenticateRootTopology(rt)) { - // Set supernodes if root topology signature is valid - RR->topology->setSupernodes(Dictionary(rt.get("supernodes",""))); // set supernodes from root-topology - - // If root-topology contains noupdate=1, disable further updates and only use what was on disk - impl->disableRootTopologyUpdates = (Utils::strToInt(rt.get("noupdate","0").c_str()) > 0); - } else { - // Revert to built-in defaults if root topology fails signature check - LOG("%s failed signature check, using built-in defaults instead",rootTopologyPath.c_str()); - Utils::rm(rootTopologyPath.c_str()); - RR->topology->setSupernodes(Dictionary(Dictionary(ZT_DEFAULTS.defaultRootTopology).get("supernodes",""))); - impl->disableRootTopologyUpdates = false; - } - } catch ( ... ) { - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format"); - } - } else { - try { - Dictionary rt(impl->overrideRootTopology); - RR->topology->setSupernodes(Dictionary(rt.get("supernodes",""))); - impl->disableRootTopologyUpdates = true; - } catch ( ... ) { - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format"); - } - } - - // Delete peers.persist if it exists -- legacy file, just takes up space - Utils::rm(std::string(RR->homePath + ZT_PATH_SEPARATOR_S + "peers.persist").c_str()); - } catch (std::bad_alloc &exc) { - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure"); - } catch (std::runtime_error &exc) { - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,exc.what()); - } catch ( ... ) { - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization"); - } - - // Core I/O loop - try { - /* Shut down if this file exists but fails to open. This is used on Mac to - * shut down automatically on .app deletion by symlinking this to the - * Info.plist file inside the ZeroTier One application. This causes the - * service to die when the user throws away the app, allowing uninstallation - * in the natural Mac way. */ - std::string shutdownIfUnreadablePath(RR->homePath + ZT_PATH_SEPARATOR_S + "shutdownIfUnreadable"); - - uint64_t lastNetworkAutoconfCheck = Utils::now() - 5000ULL; // check autoconf again after 5s for startup - uint64_t lastPingCheck = 0; - uint64_t lastClean = Utils::now(); // don't need to do this immediately - uint64_t lastMulticastCheck = 0; - uint64_t lastSupernodePingCheck = 0; - uint64_t lastBeacon = 0; - uint64_t lastRootTopologyFetch = 0; - uint64_t lastShutdownIfUnreadableCheck = 0; - long lastDelayDelta = 0; - - RR->timeOfLastResynchronize = Utils::now(); - - // We are up and running - RR->initialized = true; - - while (impl->reasonForTermination == NODE_RUNNING) { - uint64_t now = Utils::now(); - bool resynchronize = false; - - /* This is how the service automatically shuts down when the OSX .app is - * thrown in the trash. It's not used on any other platform for now but - * could do similar things. It's disabled on Windows since it doesn't really - * work there. */ -#ifdef __UNIX_LIKE__ - if ((now - lastShutdownIfUnreadableCheck) > 10000) { - lastShutdownIfUnreadableCheck = now; - if (Utils::fileExists(shutdownIfUnreadablePath.c_str(),false)) { - int tmpfd = ::open(shutdownIfUnreadablePath.c_str(),O_RDONLY,0); - if (tmpfd < 0) { - return impl->terminateBecause(Node::NODE_NORMAL_TERMINATION,"shutdownIfUnreadable exists but is not readable"); - } else ::close(tmpfd); - } - } -#endif - - // If it looks like the computer slept and woke, resynchronize. - if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) { - resynchronize = true; - LOG("probable suspend/resume detected, pausing a moment for things to settle..."); - Thread::sleep(ZT_SLEEP_WAKE_SETTLE_TIME); - } - - // Supernodes do not resynchronize unless explicitly ordered via SIGHUP. - if ((resynchronize)&&(RR->topology->amSupernode())) - resynchronize = false; - - // Check for SIGHUP / force resync. - if (impl->resynchronize) { - impl->resynchronize = false; - resynchronize = true; - LOG("resynchronize forced by user, syncing with network"); - } - - if (resynchronize) { - RR->tcpTunnelingEnabled = false; // turn off TCP tunneling master switch at first, will be reenabled on persistent UDP failure - RR->timeOfLastResynchronize = now; - } - - /* Supernodes are pinged separately and more aggressively. The - * ZT_STARTUP_AGGRO parameter sets a limit on how rapidly they are - * tried, while PingSupernodesThatNeedPing contains the logic for - * determining if they need PING. */ - if ((now - lastSupernodePingCheck) >= ZT_STARTUP_AGGRO) { - lastSupernodePingCheck = now; - - uint64_t lastReceiveFromAnySupernode = 0; // function object result paramter - RR->topology->eachSupernodePeer(Topology::FindMostRecentDirectReceiveTimestamp(lastReceiveFromAnySupernode)); - - // Turn on TCP tunneling master switch if we haven't heard anything since before - // the last resynchronize and we've been trying long enough. - uint64_t tlr = RR->timeOfLastResynchronize; - if ((lastReceiveFromAnySupernode < tlr)&&((now - tlr) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT)) { - TRACE("network still unreachable after %u ms, TCP TUNNELING ENABLED",(unsigned int)ZT_TCP_TUNNEL_FAILOVER_TIMEOUT); - RR->tcpTunnelingEnabled = true; - } - - RR->topology->eachSupernodePeer(Topology::PingSupernodesThatNeedPing(RR,now)); - } - - if (resynchronize) { - RR->sm->closeTcpSockets(); - } else { - /* Periodically check for changes in our local multicast subscriptions - * and broadcast those changes to directly connected peers. */ - if ((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD) { - lastMulticastCheck = now; - try { - std::vector< SharedPtr<Network> > networks(RR->nc->networks()); - for(std::vector< SharedPtr<Network> >::const_iterator nw(networks.begin());nw!=networks.end();++nw) - (*nw)->rescanMulticastGroups(); - } catch (std::exception &exc) { - LOG("unexpected exception announcing multicast groups: %s",exc.what()); - } catch ( ... ) { - LOG("unexpected exception announcing multicast groups: (unknown)"); - } - } - - /* Periodically ping all our non-stale direct peers unless we're a supernode. - * Supernodes only ping each other (which is done above). */ - if ((!RR->topology->amSupernode())&&((now - lastPingCheck) >= ZT_PING_CHECK_DELAY)) { - lastPingCheck = now; - try { - RR->topology->eachPeer(Topology::PingPeersThatNeedPing(RR,now)); - } catch (std::exception &exc) { - LOG("unexpected exception running ping check cycle: %s",exc.what()); - } catch ( ... ) { - LOG("unexpected exception running ping check cycle: (unkonwn)"); - } - } - } - - // Update network configurations when needed. - try { - if ((resynchronize)||((now - lastNetworkAutoconfCheck) >= ZT_NETWORK_AUTOCONF_CHECK_DELAY)) { - lastNetworkAutoconfCheck = now; - std::vector< SharedPtr<Network> > nets(RR->nc->networks()); - for(std::vector< SharedPtr<Network> >::iterator n(nets.begin());n!=nets.end();++n) { - if ((now - (*n)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY) - (*n)->requestConfiguration(); - } - } - } catch ( ... ) { - LOG("unexpected exception updating network configurations (non-fatal, will retry)"); - } - - // Do periodic tasks in submodules. - if ((now - lastClean) >= ZT_DB_CLEAN_PERIOD) { - lastClean = now; - try { - RR->topology->clean(now); - } catch ( ... ) { - LOG("unexpected exception in Topology::clean() (non-fatal)"); - } - try { - RR->mc->clean(now); - } catch ( ... ) { - LOG("unexpected exception in Multicaster::clean() (non-fatal)"); - } - try { - RR->nc->clean(); - } catch ( ... ) { - LOG("unexpected exception in NodeConfig::clean() (non-fatal)"); - } - try { - if (RR->updater) - RR->updater->checkIfMaxIntervalExceeded(now); - } catch ( ... ) { - LOG("unexpected exception in SoftwareUpdater::checkIfMaxIntervalExceeded() (non-fatal)"); - } - } - - // Send beacons to physical local LANs - try { - if ((resynchronize)||((now - lastBeacon) >= ZT_BEACON_INTERVAL)) { - lastBeacon = now; - char bcn[ZT_PROTO_BEACON_LENGTH]; - void *bcnptr = bcn; - *((uint32_t *)(bcnptr)) = RR->prng->next32(); - bcnptr = bcn + 4; - *((uint32_t *)(bcnptr)) = RR->prng->next32(); - RR->identity.address().copyTo(bcn + ZT_PROTO_BEACON_IDX_ADDRESS,ZT_ADDRESS_LENGTH); - TRACE("sending LAN beacon to %s",ZT_DEFAULTS.v4Broadcast.toString().c_str()); - RR->antiRec->logOutgoingZT(bcn,ZT_PROTO_BEACON_LENGTH); - RR->sm->send(ZT_DEFAULTS.v4Broadcast,false,false,bcn,ZT_PROTO_BEACON_LENGTH); - } - } catch ( ... ) { - LOG("unexpected exception sending LAN beacon (non-fatal)"); - } - - // Check for updates to root topology (supernodes) periodically - try { - if ((now - lastRootTopologyFetch) >= ZT_UPDATE_ROOT_TOPOLOGY_CHECK_INTERVAL) { - lastRootTopologyFetch = now; - if (!impl->disableRootTopologyUpdates) { - TRACE("fetching root topology from %s",ZT_DEFAULTS.rootTopologyUpdateURL.c_str()); - RR->http->GET(ZT_DEFAULTS.rootTopologyUpdateURL,HttpClient::NO_HEADERS,60,&_cbHandleGetRootTopology,RR); - } - } - } catch ( ... ) { - LOG("unexpected exception attempting to check for root topology updates (non-fatal)"); - } - - // Sleep for loop interval or until something interesting happens. - try { - unsigned long delay = std::min((unsigned long)ZT_MAX_SERVICE_LOOP_INTERVAL,RR->sw->doTimerTasks()); - uint64_t start = Utils::now(); - RR->sm->poll(delay,&_CBztTraffic,RR); - lastDelayDelta = (long)(Utils::now() - start) - (long)delay; // used to detect sleep/wake - } catch (std::exception &exc) { - LOG("unexpected exception running Switch doTimerTasks: %s",exc.what()); - } catch ( ... ) { - LOG("unexpected exception running Switch doTimerTasks: (unknown)"); - } - } - } catch ( ... ) { - LOG("FATAL: unexpected exception in core loop: unknown exception"); - return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unexpected exception during outer main I/O loop"); - } - - return impl->terminate(); -} - -const char *Node::terminationMessage() const - throw() -{ - if ((!((_NodeImpl *)_impl)->started)||(((_NodeImpl *)_impl)->running)) - return (const char *)0; - return ((_NodeImpl *)_impl)->reasonForTerminationStr.c_str(); -} - -void Node::terminate(ReasonForTermination reason,const char *reasonText) - throw() -{ - ((_NodeImpl *)_impl)->reasonForTermination = reason; - ((_NodeImpl *)_impl)->reasonForTerminationStr = ((reasonText) ? reasonText : ""); - ((_NodeImpl *)_impl)->renv.sm->whack(); -} - -void Node::resync() - throw() -{ - ((_NodeImpl *)_impl)->resynchronize = true; - ((_NodeImpl *)_impl)->renv.sm->whack(); -} - -bool Node::online() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - if ((!RR)||(!RR->initialized)) - return false; - uint64_t now = Utils::now(); - uint64_t since = RR->timeOfLastResynchronize; - std::vector< SharedPtr<Peer> > snp(RR->topology->supernodePeers()); - for(std::vector< SharedPtr<Peer> >::const_iterator sn(snp.begin());sn!=snp.end();++sn) { - uint64_t lastRec = (*sn)->lastDirectReceive(); - if ((lastRec)&&(lastRec > since)&&((now - lastRec) < ZT_PEER_PATH_ACTIVITY_TIMEOUT)) - return true; - } - return false; -} - -bool Node::started() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - return impl->started; -} - -bool Node::running() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - return impl->running; -} - -bool Node::initialized() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - return ((RR)&&(RR->initialized)); -} - -uint64_t Node::address() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - if ((!RR)||(!RR->initialized)) - return 0; - return RR->identity.address().toInt(); -} - -void Node::join(uint64_t nwid) - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - if ((RR)&&(RR->initialized)) - RR->nc->join(nwid); -} - -void Node::leave(uint64_t nwid) - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - if ((RR)&&(RR->initialized)) - RR->nc->leave(nwid); -} - -struct GatherPeerStatistics -{ - uint64_t now; - ZT1_Node_Status *status; - inline void operator()(Topology &t,const SharedPtr<Peer> &p) - { - ++status->knownPeers; - if (p->hasActiveDirectPath(now)) - ++status->directlyConnectedPeers; - if (p->alive(now)) - ++status->alivePeers; - } -}; -void Node::status(ZT1_Node_Status *status) - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - - memset(status,0,sizeof(ZT1_Node_Status)); - - if ((!RR)||(!RR->initialized)) - return; - - Utils::scopy(status->publicIdentity,sizeof(status->publicIdentity),RR->identity.toString(false).c_str()); - RR->identity.address().toString(status->address,sizeof(status->address)); - status->rawAddress = RR->identity.address().toInt(); - - status->knownPeers = 0; - status->supernodes = RR->topology->numSupernodes(); - status->directlyConnectedPeers = 0; - status->alivePeers = 0; - GatherPeerStatistics gps; - gps.now = Utils::now(); - gps.status = status; - RR->topology->eachPeer<GatherPeerStatistics &>(gps); - - if (status->alivePeers > 0) { - double dlsr = (double)status->directlyConnectedPeers / (double)status->alivePeers; - if (dlsr > 1.0) dlsr = 1.0; - if (dlsr < 0.0) dlsr = 0.0; - status->directLinkSuccessRate = (float)dlsr; - } else status->directLinkSuccessRate = 1.0f; // no connections to no active peers == 100% success at nothing - - status->online = online(); - status->running = impl->running; - status->initialized = true; -} - -struct CollectPeersAndPaths -{ - std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > > data; - inline void operator()(Topology &t,const SharedPtr<Peer> &p) { this->data.push_back(std::pair< SharedPtr<Peer>,std::vector<Path> >(p,p->paths())); } -}; -struct SortPeersAndPathsInAscendingAddressOrder -{ - inline bool operator()(const std::pair< SharedPtr<Peer>,std::vector<Path> > &a,const std::pair< SharedPtr<Peer>,std::vector<Path> > &b) const { return (a.first->address() < b.first->address()); } -}; -ZT1_Node_PeerList *Node::listPeers() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - - if ((!RR)||(!RR->initialized)) - return (ZT1_Node_PeerList *)0; - - CollectPeersAndPaths pp; - RR->topology->eachPeer<CollectPeersAndPaths &>(pp); - std::sort(pp.data.begin(),pp.data.end(),SortPeersAndPathsInAscendingAddressOrder()); - - unsigned int returnBufSize = sizeof(ZT1_Node_PeerList); - for(std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > >::iterator p(pp.data.begin());p!=pp.data.end();++p) - returnBufSize += sizeof(ZT1_Node_Peer) + (sizeof(ZT1_Node_PhysicalPath) * (unsigned int)p->second.size()); - - char *buf = (char *)::malloc(returnBufSize); - if (!buf) - return (ZT1_Node_PeerList *)0; - memset(buf,0,returnBufSize); - - ZT1_Node_PeerList *pl = (ZT1_Node_PeerList *)buf; - buf += sizeof(ZT1_Node_PeerList); - - pl->peers = (ZT1_Node_Peer *)buf; - buf += (sizeof(ZT1_Node_Peer) * pp.data.size()); - pl->numPeers = 0; - - uint64_t now = Utils::now(); - for(std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > >::iterator p(pp.data.begin());p!=pp.data.end();++p) { - ZT1_Node_Peer *prec = &(pl->peers[pl->numPeers++]); - if (p->first->remoteVersionKnown()) - Utils::snprintf(prec->remoteVersion,sizeof(prec->remoteVersion),"%u.%u.%u",p->first->remoteVersionMajor(),p->first->remoteVersionMinor(),p->first->remoteVersionRevision()); - p->first->address().toString(prec->address,sizeof(prec->address)); - prec->rawAddress = p->first->address().toInt(); - prec->latency = p->first->latency(); - prec->role = RR->topology->isSupernode(p->first->address()) ? ZT1_Node_Peer_SUPERNODE : ZT1_Node_Peer_NODE; - - prec->paths = (ZT1_Node_PhysicalPath *)buf; - buf += sizeof(ZT1_Node_PhysicalPath) * p->second.size(); - - prec->numPaths = 0; - for(std::vector<Path>::iterator pi(p->second.begin());pi!=p->second.end();++pi) { - ZT1_Node_PhysicalPath *path = &(prec->paths[prec->numPaths++]); - path->type = (ZT1_Node_PhysicalPathType)pi->type(); - if (pi->address().isV6()) { - path->address.type = ZT1_Node_PhysicalAddress_TYPE_IPV6; - memcpy(path->address.bits,pi->address().rawIpData(),16); - // TODO: zoneIndex not supported yet, but should be once echo-location works w/V6 - } else { - path->address.type = ZT1_Node_PhysicalAddress_TYPE_IPV4; - memcpy(path->address.bits,pi->address().rawIpData(),4); - } - path->address.port = pi->address().port(); - Utils::scopy(path->address.ascii,sizeof(path->address.ascii),pi->address().toIpString().c_str()); - path->lastSend = (pi->lastSend() > 0) ? ((long)(now - pi->lastSend())) : (long)-1; - path->lastReceive = (pi->lastReceived() > 0) ? ((long)(now - pi->lastReceived())) : (long)-1; - path->lastPing = (pi->lastPing() > 0) ? ((long)(now - pi->lastPing())) : (long)-1; - path->active = pi->active(now); - path->fixed = pi->fixed(); - } - } - - return pl; -} - -// Fills out everything but ips[] and numIps, which must be done more manually -static void _fillNetworkQueryResultBuffer(const SharedPtr<Network> &network,const SharedPtr<NetworkConfig> &nconf,ZT1_Node_Network *nbuf) -{ - nbuf->nwid = network->id(); - Utils::snprintf(nbuf->nwidHex,sizeof(nbuf->nwidHex),"%.16llx",(unsigned long long)network->id()); - if (nconf) { - Utils::scopy(nbuf->name,sizeof(nbuf->name),nconf->name().c_str()); - Utils::scopy(nbuf->description,sizeof(nbuf->description),nconf->description().c_str()); - } - Utils::scopy(nbuf->device,sizeof(nbuf->device),network->tapDeviceName().c_str()); - Utils::scopy(nbuf->statusStr,sizeof(nbuf->statusStr),Network::statusString(network->status())); - network->mac().toString(nbuf->macStr,sizeof(nbuf->macStr)); - network->mac().copyTo(nbuf->mac,sizeof(nbuf->mac)); - uint64_t lcu = network->lastConfigUpdate(); - if (lcu > 0) - nbuf->configAge = (long)(Utils::now() - lcu); - else nbuf->configAge = -1; - nbuf->status = (ZT1_Node_NetworkStatus)network->status(); - nbuf->enabled = network->enabled(); - nbuf->isPrivate = (nconf) ? nconf->isPrivate() : true; -} - -ZT1_Node_Network *Node::getNetworkStatus(uint64_t nwid) - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - - if ((!RR)||(!RR->initialized)) - return (ZT1_Node_Network *)0; - - SharedPtr<Network> network(RR->nc->network(nwid)); - if (!network) - return (ZT1_Node_Network *)0; - SharedPtr<NetworkConfig> nconf(network->config2()); - std::set<InetAddress> ips(network->ips()); - - char *buf = (char *)::malloc(sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ips.size())); - if (!buf) - return (ZT1_Node_Network *)0; - memset(buf,0,sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ips.size())); - - ZT1_Node_Network *nbuf = (ZT1_Node_Network *)buf; - buf += sizeof(ZT1_Node_Network); - - _fillNetworkQueryResultBuffer(network,nconf,nbuf); - - nbuf->ips = (ZT1_Node_PhysicalAddress *)buf; - nbuf->numIps = 0; - for(std::set<InetAddress>::iterator ip(ips.begin());ip!=ips.end();++ip) { - ZT1_Node_PhysicalAddress *ipb = &(nbuf->ips[nbuf->numIps++]); - if (ip->isV6()) { - ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV6; - memcpy(ipb->bits,ip->rawIpData(),16); - } else { - ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV4; - memcpy(ipb->bits,ip->rawIpData(),4); - } - ipb->port = ip->port(); - Utils::scopy(ipb->ascii,sizeof(ipb->ascii),ip->toIpString().c_str()); - } - - return nbuf; -} - -ZT1_Node_NetworkList *Node::listNetworks() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - - if ((!RR)||(!RR->initialized)) - return (ZT1_Node_NetworkList *)0; - - std::vector< SharedPtr<Network> > networks(RR->nc->networks()); - std::vector< SharedPtr<NetworkConfig> > nconfs(networks.size()); - std::vector< std::set<InetAddress> > ipsv(networks.size()); - - unsigned long returnBufSize = sizeof(ZT1_Node_NetworkList); - for(unsigned long i=0;i<networks.size();++i) { - nconfs[i] = networks[i]->config2(); // note: can return NULL - ipsv[i] = networks[i]->ips(); - returnBufSize += sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * (unsigned int)ipsv[i].size()); - } - - char *buf = (char *)::malloc(returnBufSize); - if (!buf) - return (ZT1_Node_NetworkList *)0; - memset(buf,0,returnBufSize); - - ZT1_Node_NetworkList *nl = (ZT1_Node_NetworkList *)buf; - buf += sizeof(ZT1_Node_NetworkList); - - nl->networks = (ZT1_Node_Network *)buf; - buf += sizeof(ZT1_Node_Network) * networks.size(); - - for(unsigned long i=0;i<networks.size();++i) { - ZT1_Node_Network *nbuf = &(nl->networks[nl->numNetworks++]); - - _fillNetworkQueryResultBuffer(networks[i],nconfs[i],nbuf); - - nbuf->ips = (ZT1_Node_PhysicalAddress *)buf; - buf += sizeof(ZT1_Node_PhysicalAddress) * ipsv[i].size(); - - nbuf->numIps = 0; - for(std::set<InetAddress>::iterator ip(ipsv[i].begin());ip!=ipsv[i].end();++ip) { - ZT1_Node_PhysicalAddress *ipb = &(nbuf->ips[nbuf->numIps++]); - if (ip->isV6()) { - ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV6; - memcpy(ipb->bits,ip->rawIpData(),16); - } else { - ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV4; - memcpy(ipb->bits,ip->rawIpData(),4); - } - ipb->port = ip->port(); - Utils::scopy(ipb->ascii,sizeof(ipb->ascii),ip->toIpString().c_str()); - } - } - - return nl; -} - -void Node::freeQueryResult(void *qr) - throw() -{ - if (qr) - ::free(qr); -} - -bool Node::updateCheck() - throw() -{ - _NodeImpl *impl = (_NodeImpl *)_impl; - RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv); - if (RR->updater) { - RR->updater->checkNow(); - return true; - } - return false; -} - -class _VersionStringMaker -{ -public: - char vs[32]; - _VersionStringMaker() - { - Utils::snprintf(vs,sizeof(vs),"%d.%d.%d",(int)ZEROTIER_ONE_VERSION_MAJOR,(int)ZEROTIER_ONE_VERSION_MINOR,(int)ZEROTIER_ONE_VERSION_REVISION); - } - ~_VersionStringMaker() {} -}; -static const _VersionStringMaker __versionString; - -const char *Node::versionString() throw() { return __versionString.vs; } - -unsigned int Node::versionMajor() throw() { return ZEROTIER_ONE_VERSION_MAJOR; } -unsigned int Node::versionMinor() throw() { return ZEROTIER_ONE_VERSION_MINOR; } -unsigned int Node::versionRevision() throw() { return ZEROTIER_ONE_VERSION_REVISION; } - -} // namespace ZeroTier diff --git a/attic/Node.hpp b/attic/Node.hpp deleted file mode 100644 index c75b884f..00000000 --- a/attic/Node.hpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_NODE_HPP -#define ZT_NODE_HPP - -#include <stdint.h> - -#include "../include/ZeroTierOne.h" - -namespace ZeroTier { - -class EthernetTapFactory; -class RoutingTable; -class SocketManager; -class NetworkConfigMaster; - -/** - * A ZeroTier One node - */ -class Node -{ -public: - /** - * Returned by node main if/when it terminates - */ - enum ReasonForTermination - { - /** - * Node is currently in run() - */ - NODE_RUNNING = 0, - - /** - * Node is shutting down for normal reasons, including a signal - */ - NODE_NORMAL_TERMINATION = 1, - - /** - * An upgrade is available. Its path is in reasonForTermination(). - */ - NODE_RESTART_FOR_UPGRADE = 2, - - /** - * A serious unrecoverable error has occurred. - */ - NODE_UNRECOVERABLE_ERROR = 3, - - /** - * An address collision occurred (typically this should cause re-invocation with resetIdentity set to true) - */ - NODE_ADDRESS_COLLISION = 4 - }; - - /** - * Create a new node - * - * The node is not executed until run() is called. The supplied tap factory - * and routing table must not be freed until the node is no longer - * executing. Node does not delete these objects; the caller still owns - * them. - * - * @param hp Home directory path or NULL for system-wide default for this platform - * @param tf Ethernet tap factory for platform network stack - * @param sm Socket manager for physical network I/O - * @param nm Network configuration master or NULL for none - * @param resetIdentity If true, delete identity before starting and regenerate - * @param overrideRootTopology Override root topology with this dictionary (in string serialized format) and do not update (default: NULL for none) - */ - Node( - const char *hp, - EthernetTapFactory *tf, - SocketManager *sm, - NetworkConfigMaster *nm, - bool resetIdentity, - const char *overrideRootTopology = (const char *)0) throw(); - - ~Node(); - - /** - * Execute node in current thread, return on shutdown - * - * @return Reason for termination - */ - ReasonForTermination run() - throw(); - - /** - * Obtain a human-readable reason for node termination - * - * @return Reason for node termination or NULL if run() has not returned - */ - const char *terminationMessage() const - throw(); - - /** - * Terminate this node, causing run() to return - * - * @param reason Reason for termination - * @param reasonText Text to be returned by terminationMessage() - */ - void terminate(ReasonForTermination reason,const char *reasonText) - throw(); - - /** - * Forget p2p links now and resynchronize with peers - * - * This can be used if the containing application knows its network environment has - * changed. ZeroTier itself tries to detect such changes, but is not always successful. - */ - void resync() - throw(); - - /** - * @return True if we appear to be online in some viable capacity - */ - bool online() - throw(); - - /** - * @return True if run() has been called - */ - bool started() - throw(); - - /** - * @return True if run() has not yet returned - */ - bool running() - throw(); - - /** - * @return True if initialization phase of startup is complete - */ - bool initialized() - throw(); - - /** - * @return This node's address (in least significant 40 bits of 64-bit int) or 0 if not yet initialized - */ - uint64_t address() - throw(); - - /** - * Join a network - * - * Use getNetworkStatus() to check the network's status after joining. If you - * are already a member of the network, this does nothing. - * - * @param nwid 64-bit network ID - */ - void join(uint64_t nwid) - throw(); - - /** - * Leave a network (if a member) - * - * @param nwid 64-bit network ID - */ - void leave(uint64_t nwid) - throw(); - - /** - * Get the status of this node - * - * @param status Buffer to fill with status information - */ - void status(ZT1_Node_Status *status) - throw(); - - /** - * @return List of known peers or NULL on failure - */ - ZT1_Node_PeerList *listPeers() - throw(); - - /** - * @param nwid 64-bit network ID - * @return Network status or NULL if we are not a member of this network - */ - ZT1_Node_Network *getNetworkStatus(uint64_t nwid) - throw(); - - /** - * @return List of networks we've joined or NULL on failure - */ - ZT1_Node_NetworkList *listNetworks() - throw(); - - /** - * Free a query result buffer - * - * Use this to free the return values of listNetworks(), listPeers(), etc. - * - * @param qr Query result buffer - */ - void freeQueryResult(void *qr) - throw(); - - /** - * Check for software updates (if enabled) (updates will eventually get factored out of node/) - */ - bool updateCheck() - throw(); - - static const char *versionString() throw(); - static unsigned int versionMajor() throw(); - static unsigned int versionMinor() throw(); - static unsigned int versionRevision() throw(); - -private: - // Nodes are not copyable - Node(const Node&); - const Node& operator=(const Node&); - - void *const _impl; // private implementation -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/WindowsEthernetTapFactory.cpp b/attic/WindowsEthernetTapFactory.cpp deleted file mode 100644 index 996460a1..00000000 --- a/attic/WindowsEthernetTapFactory.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "WindowsEthernetTapFactory.hpp" -#include "WindowsEthernetTap.hpp" - -namespace ZeroTier { - -WindowsEthernetTapFactory::Env::Env() -{ -#ifdef _WIN64 - is64Bit = TRUE; - devcon = "\\devcon_x64.exe"; - tapDriver = "\\tap-windows\\x64\\zttap200.inf"; -#else - is64Bit = FALSE; - IsWow64Process(GetCurrentProcess(),&is64Bit); - devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); - tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); -#endif -} -const WindowsEthernetTapFactory::Env WindowsEthernetTapFactory::WINENV; - -WindowsEthernetTapFactory::WindowsEthernetTapFactory(const char *pathToHelpers) : - _pathToHelpers(pathToHelpers) -{ -} - -WindowsEthernetTapFactory::~WindowsEthernetTapFactory() -{ - Mutex::Lock _l(_devices_m); - for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) - delete *d; -} - -EthernetTap *WindowsEthernetTapFactory::open( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg) -{ - Mutex::Lock _l(_devices_m); - EthernetTap *t = new WindowsEthernetTap(_pathToHelpers.c_str(),mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg); - _devices.push_back(t); - return t; -} - -void WindowsEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices) -{ - if (!tap) - return; - - std::string instanceId(((WindowsEthernetTap *)tap)->instanceId()); - Mutex::Lock _l(_devices_m); - - for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) { - if (*d == tap) { - _devices.erase(d); - break; - } - } - - delete tap; - - if (destroyPersistentDevices) - _deletePersistentTapDevice(_pathToHelpers.c_str(),instanceId.c_str()); -} - -void WindowsEthernetTapFactory::destroyAllPersistentTapDevices(const char *pathToHelpers) -{ - char subkeyName[4096]; - char subkeyClass[4096]; - char data[4096]; - - std::set<std::string> instanceIdPathsToRemove; - { - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - return; - - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - if (!strnicmp(data,"zttap",5)) { - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - if (instanceIdPath.length() != 0) - instanceIdPathsToRemove.insert(instanceIdPath); - } - } - } else break; // end of list or failure - } - - RegCloseKey(nwAdapters); - } - - for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) - _deletePersistentTapDevice(pathToHelpers,iidp->c_str()); -} - -void WindowsEthernetTapFactory::_deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId) -{ - HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - SetFilePointer(devconLog,0,0,FILE_END); - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); -} - -} // namespace ZeroTier diff --git a/attic/WindowsEthernetTapFactory.hpp b/attic/WindowsEthernetTapFactory.hpp deleted file mode 100644 index 47e146e3..00000000 --- a/attic/WindowsEthernetTapFactory.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_WINDOWSETHERNETTAPFACTORY_HPP -#define ZT_WINDOWSETHERNETTAPFACTORY_HPP - -#include <vector> -#include <string> - -#include "../node/EthernetTapFactory.hpp" -#include "../node/Mutex.hpp" - -namespace ZeroTier { - -class WindowsEthernetTapFactory : public EthernetTapFactory -{ -public: - class Env - { - public: - Env(); - BOOL is64Bit; // true if WIN64 or WoW64 (32-bit binary on 64-bit architecture) - const char *devcon; // name of devcon binary in pathToHelpers to use - const char *tapDriver; // relative path to driver under pathToHelpers to use - }; - - /** - * Constants related to Windows environment, computed on program start - */ - static const Env WINENV; - - /** - * @param pathToHelpers Path to devcon32.exe, devcon64.exe, and other required helper binaries (ZeroTier running directory) - */ - WindowsEthernetTapFactory(const char *pathToHelpers); - virtual ~WindowsEthernetTapFactory(); - - virtual EthernetTap *open( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg); - virtual void close(EthernetTap *tap,bool destroyPersistentDevices); - - /** - * Uninstalls all persistent tap devices in the system belonging to ZeroTier - * - * This is for uninstallation. Do not call this while tap devices are active. - */ - static void destroyAllPersistentTapDevices(const char *pathToHelpers); - -private: - static void _deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId); - - std::string _pathToHelpers; - std::vector<EthernetTap *> _devices; - Mutex _devices_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/main.cpp b/attic/main.cpp deleted file mode 100644 index 60a03b7b..00000000 --- a/attic/main.cpp +++ /dev/null @@ -1,887 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -// Uncomment on Windows to assume -C and run in console instead of service -// Useful for Visual Studio debugging (launch VS as Administrator to run) -//#define ZT_WIN_RUN_IN_CONSOLE - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <errno.h> - -#include <string> -#include <stdexcept> - -#include "node/Constants.hpp" - -#ifdef __WINDOWS__ -#include <WinSock2.h> -#include <Windows.h> -#include <tchar.h> -#include <wchar.h> -#include <lmcons.h> -#include <newdev.h> -#include <atlbase.h> -#include "windows/ZeroTierOne/ServiceInstaller.h" -#include "windows/ZeroTierOne/ServiceBase.h" -#include "windows/ZeroTierOne/ZeroTierOneService.h" -#else -#include <unistd.h> -#include <pwd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#endif - -#include "node/Constants.hpp" - -#include "node/Defaults.hpp" -#include "node/Utils.hpp" -#include "node/Node.hpp" -#include "node/C25519.hpp" -#include "node/Identity.hpp" -#include "node/Thread.hpp" -#include "node/CertificateOfMembership.hpp" -#include "node/EthernetTapFactory.hpp" -#include "node/SocketManager.hpp" - -#include "control/NodeControlClient.hpp" -#include "control/NodeControlService.hpp" - -#include "osdep/NativeSocketManager.hpp" - -#ifdef ZT_ENABLE_NETCONF_MASTER -#include "netconf/SqliteNetworkConfigMaster.hpp" -#endif // ZT_ENABLE_NETCONF_MASTER - -#ifdef __WINDOWS__ -#include "osdep/WindowsEthernetTapFactory.hpp" -#define ZTCreatePlatformEthernetTapFactory (new WindowsEthernetTapFactory(homeDir)) -#endif // __WINDOWS__ - -#ifdef __LINUX__ -#include "osdep/LinuxEthernetTapFactory.hpp" -#define ZTCreatePlatformEthernetTapFactory (new LinuxEthernetTapFactory()) -#endif // __LINUX__ - -#ifdef __APPLE__ -#include "osdep/OSXEthernetTapFactory.hpp" -#define ZTCreatePlatformEthernetTapFactory (new OSXEthernetTapFactory(homeDir,"tap.kext")) -#endif // __APPLE__ - -#ifndef ZTCreatePlatformEthernetTapFactory -#ifdef __BSD__ -#include "osdep/BSDEthernetTapFactory.hpp" -#define ZTCreatePlatformEthernetTapFactory (new BSDEthernetTapFactory()) -#else -#error Sorry, this platform has no osdep/ implementation yet. Fork me on GitHub and add one? -#endif // __BSD__ -#endif // ZTCreatePlatformEthernetTapFactory - -using namespace ZeroTier; - -static Node *node = (Node *)0; - -namespace ZeroTierCLI { // --------------------------------------------------- - -static void printHelp(FILE *out,const char *cn) -{ - fprintf(out,"Usage: %s <command> (use 'help' for help)"ZT_EOL_S,cn); -} - -static void _CBresultHandler(void *arg,const char *line) -{ - if (line) { - if ((line[0] == '.')&&(line[1] == (char)0)) { - fflush(stdout); - ::exit(0); // terminate CLI on end of message - } else { - fprintf(stdout,"%s"ZT_EOL_S,line); - } - } -} - -#ifdef __WINDOWS__ -static int main(const char *homeDir,int argc,_TCHAR* argv[]) -#else -static int main(const char *homeDir,int argc,char **argv) -#endif -{ - if (argc < 2) { - printHelp(stdout,argv[0]); - return 1; - } - - std::string query; - for(int i=1;i<argc;++i) { - if (argv[i][0] == '-') { - switch(argv[i][1]) { - case 'q': // ignore -q since it's used to invoke this - break; - case 'h': - default: - printHelp(stdout,argv[0]); - return 1; - } - } else if ((!homeDir)||(strcmp(homeDir,argv[i]))) { - if (query.length()) - query.push_back(' '); - query.append(argv[i]); - } - } - if (!query.length()) { - printHelp(stdout,argv[0]); - return 1; - } - - if (!homeDir) - homeDir = ZT_DEFAULTS.defaultHomePath.c_str(); - - try { - std::string buf; - if (!Utils::readFile((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),buf)) { - fprintf(stderr,"%s: fatal error: unable to read node address from identity.public in home path"ZT_EOL_S,argv[0]); - return 1; - } - Identity id; - if (!id.fromString(buf)) { - fprintf(stderr,"%s: fatal error: unable to read node address from identity.public in home path"ZT_EOL_S,argv[0]); - return 1; - } - - std::string authToken(NodeControlClient::getAuthToken((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),false)); - if (!authToken.length()) - authToken = NodeControlClient::getAuthToken(NodeControlClient::authTokenDefaultUserPath(),false); - if (!authToken.length()) { - fprintf(stderr,"%s: fatal error: unable to read authentication token from home path or user home"ZT_EOL_S,argv[0]); - return 1; - } - - NodeControlClient client((std::string(ZT_IPC_ENDPOINT_BASE) + id.address().toString()).c_str(),authToken.c_str(),&_CBresultHandler,(void *)0); - const char *err = client.error(); - if (err) { - fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],err); - return 1; - } - client.send(query.c_str()); - for(;;) { Thread::sleep(60000); } // exit() is called at end of message from handler - } catch (std::exception &exc) { - fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],exc.what()); - return 1; - } catch ( ... ) { - fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (unknown exception)"ZT_EOL_S,argv[0]); - return 1; - } - - return 0; -} - -} // namespace ZeroTierCLI --------------------------------------------------- - -namespace ZeroTierIdTool { // ------------------------------------------------ - -static void printHelp(FILE *out,const char *pn) -{ - fprintf(out,"Usage: %s <command> [<args>]"ZT_EOL_S""ZT_EOL_S"Commands:"ZT_EOL_S,pn); - fprintf(out," generate [<identity.secret>] [<identity.public>]"ZT_EOL_S); - fprintf(out," validate <identity.secret/public>"ZT_EOL_S); - fprintf(out," getpublic <identity.secret>"ZT_EOL_S); - fprintf(out," sign <identity.secret> <file>"ZT_EOL_S); - fprintf(out," verify <identity.secret/public> <file> <signature>"ZT_EOL_S); - fprintf(out," mkcom <identity.secret> [<id,value,maxDelta> ...] (hexadecimal integers)"ZT_EOL_S); -} - -static Identity getIdFromArg(char *arg) -{ - Identity id; - if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line - if (id.fromString(arg)) - return id; - } else { // identity is to be read from a file - std::string idser; - if (Utils::readFile(arg,idser)) { - if (id.fromString(idser)) - return id; - } - } - return Identity(); -} - -#ifdef __WINDOWS__ -static int main(int argc,_TCHAR* argv[]) -#else -static int main(int argc,char **argv) -#endif -{ - if (argc < 2) { - printHelp(stdout,argv[0]); - return 1; - } - - if (!strcmp(argv[1],"generate")) { - Identity id; - id.generate(); - std::string idser = id.toString(true); - if (argc >= 3) { - if (!Utils::writeFile(argv[2],idser)) { - fprintf(stderr,"Error writing to %s"ZT_EOL_S,argv[2]); - return 1; - } else printf("%s written"ZT_EOL_S,argv[2]); - if (argc >= 4) { - idser = id.toString(false); - if (!Utils::writeFile(argv[3],idser)) { - fprintf(stderr,"Error writing to %s"ZT_EOL_S,argv[3]); - return 1; - } else printf("%s written"ZT_EOL_S,argv[3]); - } - } else printf("%s",idser.c_str()); - } else if (!strcmp(argv[1],"validate")) { - if (argc < 3) { - printHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]); - return 1; - } - - if (!id.locallyValidate()) { - fprintf(stderr,"%s FAILED validation."ZT_EOL_S,argv[2]); - return 1; - } else printf("%s is a valid identity"ZT_EOL_S,argv[2]); - } else if (!strcmp(argv[1],"getpublic")) { - if (argc < 3) { - printHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]); - return 1; - } - - printf("%s",id.toString(false).c_str()); - } else if (!strcmp(argv[1],"sign")) { - if (argc < 4) { - printHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]); - return 1; - } - - if (!id.hasPrivate()) { - fprintf(stderr,"%s does not contain a private key (must use private to sign)"ZT_EOL_S,argv[2]); - return 1; - } - - std::string inf; - if (!Utils::readFile(argv[3],inf)) { - fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]); - return 1; - } - C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length()); - printf("%s",Utils::hex(signature.data,(unsigned int)signature.size()).c_str()); - } else if (!strcmp(argv[1],"verify")) { - if (argc < 4) { - printHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]); - return 1; - } - - std::string inf; - if (!Utils::readFile(argv[3],inf)) { - fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]); - return 1; - } - - std::string signature(Utils::unhex(argv[4])); - if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) { - printf("%s signature valid"ZT_EOL_S,argv[3]); - } else { - fprintf(stderr,"%s signature check FAILED"ZT_EOL_S,argv[3]); - return 1; - } - } else if (!strcmp(argv[1],"mkcom")) { - if (argc < 3) { - printHelp(stdout,argv[0]); - return 1; - } - - Identity id = getIdFromArg(argv[2]); - if ((!id)||(!id.hasPrivate())) { - fprintf(stderr,"Identity argument invalid, does not include private key, or file unreadable: %s"ZT_EOL_S,argv[2]); - return 1; - } - - CertificateOfMembership com; - for(int a=3;a<argc;++a) { - std::vector<std::string> params(Utils::split(argv[a],",","","")); - if (params.size() == 3) { - uint64_t qId = Utils::hexStrToU64(params[0].c_str()); - uint64_t qValue = Utils::hexStrToU64(params[1].c_str()); - uint64_t qMaxDelta = Utils::hexStrToU64(params[2].c_str()); - com.setQualifier(qId,qValue,qMaxDelta); - } - } - if (!com.sign(id)) { - fprintf(stderr,"Signature of certificate of membership failed."ZT_EOL_S); - return 1; - } - - printf("%s",com.toString().c_str()); - } else { - printHelp(stdout,argv[0]); - return 1; - } - - return 0; -} - -} // namespace ZeroTierIdTool ------------------------------------------------ - -#ifdef __UNIX_LIKE__ -static void sighandlerHup(int sig) -{ - Node *n = node; - if (n) - n->resync(); -} -static void sighandlerQuit(int sig) -{ - Node *n = node; - if (n) - n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal"); - else exit(0); -} -#endif - -#ifdef __WINDOWS__ -// Console signal handler routine to allow CTRL+C to work, mostly for testing -static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType) -{ - switch(dwCtrlType) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - case CTRL_CLOSE_EVENT: - case CTRL_SHUTDOWN_EVENT: - Node *n = node; - if (n) - n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal"); - return TRUE; - } - return FALSE; -} - -// Pokes a hole in the Windows firewall (advfirewall) for the running program -static void _winPokeAHole() -{ - char myPath[MAX_PATH]; - DWORD ps = GetModuleFileNameA(NULL,myPath,sizeof(myPath)); - if ((ps > 0)&&(ps < (DWORD)sizeof(myPath))) { - STARTUPINFOA startupInfo; - PROCESS_INFORMATION processInfo; - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall delete rule name=\"ZeroTier One\" program=\"") + myPath + "\"").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=in action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=out action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - } -} - -// Returns true if this is running as the local administrator -static BOOL IsCurrentUserLocalAdministrator(void) -{ - BOOL fReturn = FALSE; - DWORD dwStatus; - DWORD dwAccessMask; - DWORD dwAccessDesired; - DWORD dwACLSize; - DWORD dwStructureSize = sizeof(PRIVILEGE_SET); - PACL pACL = NULL; - PSID psidAdmin = NULL; - - HANDLE hToken = NULL; - HANDLE hImpersonationToken = NULL; - - PRIVILEGE_SET ps; - GENERIC_MAPPING GenericMapping; - - PSECURITY_DESCRIPTOR psdAdmin = NULL; - SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; - - const DWORD ACCESS_READ = 1; - const DWORD ACCESS_WRITE = 2; - - __try - { - if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,TRUE,&hToken)) - { - if (GetLastError() != ERROR_NO_TOKEN) - __leave; - if (!OpenProcessToken(GetCurrentProcess(),TOKEN_DUPLICATE|TOKEN_QUERY, &hToken)) - __leave; - } - if (!DuplicateToken (hToken, SecurityImpersonation,&hImpersonationToken)) - __leave; - if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, &psidAdmin)) - __leave; - psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); - if (psdAdmin == NULL) - __leave; - if (!InitializeSecurityDescriptor(psdAdmin,SECURITY_DESCRIPTOR_REVISION)) - __leave; - dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD); - pACL = (PACL)LocalAlloc(LPTR, dwACLSize); - if (pACL == NULL) - __leave; - if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) - __leave; - dwAccessMask= ACCESS_READ | ACCESS_WRITE; - if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin)) - __leave; - if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) - __leave; - - SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); - SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE); - - if (!IsValidSecurityDescriptor(psdAdmin)) - __leave; - dwAccessDesired = ACCESS_READ; - - GenericMapping.GenericRead = ACCESS_READ; - GenericMapping.GenericWrite = ACCESS_WRITE; - GenericMapping.GenericExecute = 0; - GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; - - if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired, - &GenericMapping, &ps, &dwStructureSize, &dwStatus, - &fReturn)) - { - fReturn = FALSE; - __leave; - } - } - __finally - { - // Clean up. - if (pACL) LocalFree(pACL); - if (psdAdmin) LocalFree(psdAdmin); - if (psidAdmin) FreeSid(psidAdmin); - if (hImpersonationToken) CloseHandle (hImpersonationToken); - if (hToken) CloseHandle (hToken); - } - - return fReturn; -} -#endif // __WINDOWS__ - -// --------------------------------------------------------------------------- - -static void printHelp(const char *cn,FILE *out) -{ - fprintf(out,"ZeroTier One version %d.%d.%d"ZT_EOL_S"(c)2011-2014 ZeroTier Networks LLC"ZT_EOL_S,Node::versionMajor(),Node::versionMinor(),Node::versionRevision()); - fprintf(out,"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S); -#ifdef ZT_AUTO_UPDATE - fprintf(out,"Auto-update enabled build, will update from URL:"ZT_EOL_S); - fprintf(out," %s"ZT_EOL_S,ZT_DEFAULTS.updateLatestNfoURL.c_str()); - fprintf(out,"Update authentication signing authorities: "ZT_EOL_S); - int no = 0; - for(std::map< Address,Identity >::const_iterator sa(ZT_DEFAULTS.updateAuthorities.begin());sa!=ZT_DEFAULTS.updateAuthorities.end();++sa) { - if (no == 0) - fprintf(out," %s",sa->first.toString().c_str()); - else fprintf(out,", %s",sa->first.toString().c_str()); - if (++no == 6) { - fprintf(out,ZT_EOL_S); - no = 0; - } - } - fprintf(out,ZT_EOL_S""ZT_EOL_S); -#else - fprintf(out,"Auto-updates not enabled on this build. You must update manually."ZT_EOL_S""ZT_EOL_S); -#endif - fprintf(out,"Usage: %s [-switches] [home directory] [-q <query>]"ZT_EOL_S""ZT_EOL_S,cn); - fprintf(out,"Available switches:"ZT_EOL_S); - fprintf(out," -h - Display this help"ZT_EOL_S); - fprintf(out," -v - Show version"ZT_EOL_S); - fprintf(out," -p<port> - Port for UDP (default: 9993)"ZT_EOL_S); - fprintf(out," -t<port> - Port for TCP (default: disabled)"ZT_EOL_S); - //fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S); -#ifdef __UNIX_LIKE__ - fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)"ZT_EOL_S); -#endif - fprintf(out," -q - Send a query to a running service (zerotier-cli)"ZT_EOL_S); - fprintf(out," -i - Generate and manage identities (zerotier-idtool)"ZT_EOL_S); -#ifdef __WINDOWS__ - fprintf(out," -C - Run from command line instead of as service (Windows)"ZT_EOL_S); - fprintf(out," -I - Install Windows service (Windows)"ZT_EOL_S); - fprintf(out," -R - Uninstall Windows service (Windows)"ZT_EOL_S); - fprintf(out," -D - Load tap driver into system driver store (Windows)"ZT_EOL_S); -#endif -} - -#ifdef __WINDOWS__ -int _tmain(int argc, _TCHAR* argv[]) -#else -int main(int argc,char **argv) -#endif -{ -#ifdef __UNIX_LIKE__ - signal(SIGHUP,&sighandlerHup); - signal(SIGPIPE,SIG_IGN); - signal(SIGUSR1,SIG_IGN); - signal(SIGUSR2,SIG_IGN); - signal(SIGALRM,SIG_IGN); - signal(SIGINT,&sighandlerQuit); - signal(SIGTERM,&sighandlerQuit); - signal(SIGQUIT,&sighandlerQuit); - - /* Ensure that there are no inherited file descriptors open from a previous - * incarnation. This is a hack to ensure that GitHub issue #61 or variants - * of it do not return, and should not do anything otherwise bad. */ - { - int mfd = STDIN_FILENO; - if (STDOUT_FILENO > mfd) mfd = STDOUT_FILENO; - if (STDERR_FILENO > mfd) mfd = STDERR_FILENO; - for(int f=mfd+1;f<1024;++f) - ::close(f); - } -#endif - -#ifdef __WINDOWS__ - WSADATA wsaData; - WSAStartup(MAKEWORD(2,2),&wsaData); -#endif - - if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI"))) - return ZeroTierCLI::main((const char *)0,argc,argv); - if ((strstr(argv[0],"zerotier-idtool"))||(strstr(argv[0],"ZEROTIER-IDTOOL"))) - return ZeroTierIdTool::main(argc,argv); - - const char *homeDir = (const char *)0; - unsigned int udpPort = ZT_DEFAULT_UDP_PORT; - unsigned int tcpPort = 0; - - std::string overrideRootTopology; -#ifdef __UNIX_LIKE__ - bool runAsDaemon = false; -#endif -#ifdef __WINDOWS__ -#ifdef ZT_WIN_RUN_IN_CONSOLE - bool winRunFromCommandLine = true; -#else - bool winRunFromCommandLine = false; -#endif -#endif // __WINDOWS__ - - for(int i=1;i<argc;++i) { - if (argv[i][0] == '-') { - switch(argv[i][1]) { - case 'p': - udpPort = Utils::strToUInt(argv[i] + 2); - if (udpPort > 65535) { - printHelp(argv[0],stdout); - return 1; - } - break; - case 't': - tcpPort = Utils::strToUInt(argv[i] + 2); - if (tcpPort > 65535) { - printHelp(argv[0],stdout); - return 1; - } - break; -#ifdef __UNIX_LIKE__ - case 'd': - runAsDaemon = true; - break; -#endif - case 'T': - if (argv[i][2]) { - if (!Utils::readFile(argv[i] + 2,overrideRootTopology)) { - fprintf(stderr,"%s: cannot read root topology from %s"ZT_EOL_S,argv[0],argv[i] + 2); - return 1; - } - } else { - printHelp(argv[0],stdout); - return 1; - } - break; - case 'v': - printf("%s"ZT_EOL_S,Node::versionString()); - return 0; - case 'q': - if (argv[i][2]) { - printHelp(argv[0],stdout); - return 0; - } else return ZeroTierCLI::main(homeDir,argc,argv); - case 'i': - if (argv[i][2]) { - printHelp(argv[0],stdout); - return 0; - } else return ZeroTierIdTool::main(argc,argv); -#ifdef __WINDOWS__ - case 'C': - winRunFromCommandLine = true; - break; - case 'I': { // install self as service - if (IsCurrentUserLocalAdministrator() != TRUE) { - fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]); - return 1; - } - std::string ret(InstallService(ZT_SERVICE_NAME,ZT_SERVICE_DISPLAY_NAME,ZT_SERVICE_START_TYPE,ZT_SERVICE_DEPENDENCIES,ZT_SERVICE_ACCOUNT,ZT_SERVICE_PASSWORD)); - if (ret.length()) { - fprintf(stderr,"%s: unable to install service: %s"ZT_EOL_S,argv[0],ret.c_str()); - return 3; - } - return 0; - } break; - case 'R': { // uninstall self as service - if (IsCurrentUserLocalAdministrator() != TRUE) { - fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]); - return 1; - } - std::string ret(UninstallService(ZT_SERVICE_NAME)); - if (ret.length()) { - fprintf(stderr,"%s: unable to uninstall service: %s"ZT_EOL_S,argv[0],ret.c_str()); - return 3; - } - return 0; - } break; - case 'D': { // install Windows driver (since PNPUTIL.EXE seems to be weirdly unreliable) - std::string pathToInf; -#ifdef _WIN64 - pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x64\\zttap200.inf"; -#else - pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x86\\zttap200.inf"; -#endif - printf("Installing ZeroTier One virtual Ethernet port driver."ZT_EOL_S""ZT_EOL_S"NOTE: If you don't see a confirmation window to allow driver installation,"ZT_EOL_S"check to make sure it didn't appear under the installer."ZT_EOL_S); - BOOL needReboot = FALSE; - if (DiInstallDriverA(NULL,pathToInf.c_str(),DIIRFLAG_FORCE_INF,&needReboot)) { - printf("%s: driver successfully installed from %s"ZT_EOL_S,argv[0],pathToInf.c_str()); - return 0; - } else { - printf("%s: failed installing %s: %d"ZT_EOL_S,argv[0],pathToInf.c_str(),(int)GetLastError()); - return 3; - } - } break; -#endif // __WINDOWS__ - case 'h': - case '?': - default: - printHelp(argv[0],stdout); - return 0; - } - } else { - if (homeDir) { - printHelp(argv[0],stdout); - return 0; - } else homeDir = argv[i]; - } - } - if ((!homeDir)||(strlen(homeDir) == 0)) - homeDir = ZT_DEFAULTS.defaultHomePath.c_str(); - -#ifdef __UNIX_LIKE__ - if (getuid() != 0) { - fprintf(stderr,"%s: must be run as root (uid 0)\n",argv[0]); - return 1; - } - - if (runAsDaemon) { - long p = (long)fork(); - if (p < 0) { - fprintf(stderr,"%s: could not fork"ZT_EOL_S,argv[0]); - return 1; - } else if (p > 0) - return 0; // forked - // else p == 0, so we are daemonized - } - - mkdir(homeDir,0755); // will fail if it already exists, but that's fine - - { - // Write .pid file to home folder - char pidpath[4096]; - Utils::snprintf(pidpath,sizeof(pidpath),"%s/zerotier-one.pid",homeDir); - FILE *pf = fopen(pidpath,"w"); - if (pf) { - fprintf(pf,"%ld",(long)getpid()); - fclose(pf); - } - } -#endif // __UNIX_LIKE__ - -#ifdef __WINDOWS__ - if (winRunFromCommandLine) { - // Running in "interactive" mode (mostly for debugging) - if (IsCurrentUserLocalAdministrator() != TRUE) { - fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]); - return 1; - } - _winPokeAHole(); - SetConsoleCtrlHandler(&_winConsoleCtrlHandler,TRUE); - // continues on to ordinary command line execution code below... - } else { - // Running from service manager - _winPokeAHole(); - ZeroTierOneService zt1Service; - if (CServiceBase::Run(zt1Service) == TRUE) { - return 0; - } else { - fprintf(stderr,"%s: unable to start service (try -h for help)"ZT_EOL_S,argv[0]); - return 1; - } - } -#endif // __WINDOWS__ - - int exitCode = 0; - bool needsReset = false; - EthernetTapFactory *tapFactory = (EthernetTapFactory *)0; - SocketManager *socketManager = (SocketManager *)0; - NodeControlService *controlService = (NodeControlService *)0; - NetworkConfigMaster *netconfMaster = (NetworkConfigMaster *)0; - - try { - // Get or create authtoken.secret -- note that if this fails, authentication - // will always fail since an empty auth token won't work. This should always - // succeed unless something is wrong with the filesystem. - std::string authToken(NodeControlClient::getAuthToken((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),true)); - - tapFactory = ZTCreatePlatformEthernetTapFactory; - - try { - socketManager = new NativeSocketManager(udpPort,tcpPort); - } catch ( ... ) { - fprintf(stderr,"%s: unable to bind to port: %u/UDP, %u/TCP (0 == disabled)"ZT_EOL_S,argv[0],udpPort,tcpPort); - throw; - } - - node = new Node(homeDir,tapFactory,socketManager,netconfMaster,needsReset,(overrideRootTopology.length() > 0) ? overrideRootTopology.c_str() : (const char *)0); - controlService = new NodeControlService(node,authToken.c_str()); - - switch(node->run()) { -#ifdef __WINDOWS__ - case Node::NODE_RESTART_FOR_UPGRADE: { - const char *upgPath = node->terminationMessage(); - if (upgPath) { - if (!ZeroTierOneService::doStartUpgrade(std::string(upgPath))) { - exitCode = 3; - fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (doStartUpgrade failed)"ZT_EOL_S,argv[0],(upgPath) ? upgPath : "(unknown path)"); - } - } else { - exitCode = 3; - fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (no upgrade path provided)"ZT_EOL_S,argv[0],(upgPath) ? upgPath : "(unknown path)"); - } - } break; -#else // __UNIX_LIKE__ - case Node::NODE_RESTART_FOR_UPGRADE: { - const char *upgPath = node->terminationMessage(); - // On Unix-type OSes we exec() right into the upgrade. This in turn will - // end with us being re-launched either via the upgrade itself or something - // like OSX's launchd. - if (upgPath) { - Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str()); - std::string updateLogPath(homeDir); - updateLogPath.append("/autoupdate.log"); - Utils::rm(updateLogPath.c_str()); - Utils::redirectUnixOutputs(updateLogPath.c_str(),(const char *)0); - ::execl(upgPath,upgPath,(char *)0); - } - exitCode = 3; - fprintf(stderr,"%s: abnormal termination: unable to execute update at %s"ZT_EOL_S,argv[0],(upgPath) ? upgPath : "(unknown path)"); - } break; -#endif // __WINDOWS__ / __UNIX_LIKE__ - - case Node::NODE_UNRECOVERABLE_ERROR: { - exitCode = 3; - const char *termReason = node->terminationMessage(); - fprintf(stderr,"%s: abnormal termination: %s"ZT_EOL_S,argv[0],(termReason) ? termReason : "(unknown reason)"); - } break; - - default: - break; - } - } catch ( std::exception &exc ) { - fprintf(stderr,"%s: unexpected exception: %s"ZT_EOL_S,argv[0],exc.what()); - exitCode = 3; - } catch ( ... ) { - fprintf(stderr,"%s: unexpected exception: unknown exception"ZT_EOL_S,argv[0]); - exitCode = 3; - } - - delete controlService; - delete node; node = (Node *)0; - delete socketManager; - delete tapFactory; - -#ifdef __UNIX_LIKE__ - Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str()); -#endif - - return exitCode; -} diff --git a/ext/bin/tap-windows/x64/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll Binary files differindex d49d2913..d49d2913 100644 --- a/ext/bin/tap-windows/x64/WdfCoinstaller01011.dll +++ b/ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll diff --git a/ext/bin/tap-windows/x64/zttap200.cat b/ext/bin/tap-windows-ndis5/x64/zttap200.cat Binary files differindex a3769e40..a3769e40 100644 --- a/ext/bin/tap-windows/x64/zttap200.cat +++ b/ext/bin/tap-windows-ndis5/x64/zttap200.cat diff --git a/ext/bin/tap-windows/x64/zttap200.inf b/ext/bin/tap-windows-ndis5/x64/zttap200.inf index dc1a7422..dc1a7422 100644 --- a/ext/bin/tap-windows/x64/zttap200.inf +++ b/ext/bin/tap-windows-ndis5/x64/zttap200.inf diff --git a/ext/bin/tap-windows/x64/zttap200.sys b/ext/bin/tap-windows-ndis5/x64/zttap200.sys Binary files differindex 339351fb..339351fb 100644 --- a/ext/bin/tap-windows/x64/zttap200.sys +++ b/ext/bin/tap-windows-ndis5/x64/zttap200.sys diff --git a/ext/bin/tap-windows/x86/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll Binary files differindex e943ea45..e943ea45 100644 --- a/ext/bin/tap-windows/x86/WdfCoinstaller01011.dll +++ b/ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll diff --git a/ext/bin/tap-windows/x86/zttap200.cat b/ext/bin/tap-windows-ndis5/x86/zttap200.cat Binary files differindex d90ecbbe..d90ecbbe 100644 --- a/ext/bin/tap-windows/x86/zttap200.cat +++ b/ext/bin/tap-windows-ndis5/x86/zttap200.cat diff --git a/ext/bin/tap-windows/x86/zttap200.inf b/ext/bin/tap-windows-ndis5/x86/zttap200.inf index 99aac9f2..99aac9f2 100644 --- a/ext/bin/tap-windows/x86/zttap200.inf +++ b/ext/bin/tap-windows-ndis5/x86/zttap200.inf diff --git a/ext/bin/tap-windows/x86/zttap200.sys b/ext/bin/tap-windows-ndis5/x86/zttap200.sys Binary files differindex b7b11fbe..b7b11fbe 100644 --- a/ext/bin/tap-windows/x86/zttap200.sys +++ b/ext/bin/tap-windows-ndis5/x86/zttap200.sys diff --git a/ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll Binary files differnew file mode 100644 index 00000000..d49d2913 --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.cat b/ext/bin/tap-windows-ndis6/x64/zttap300.cat Binary files differnew file mode 100644 index 00000000..f1f878a3 --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x64/zttap300.cat diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.inf b/ext/bin/tap-windows-ndis6/x64/zttap300.inf new file mode 100644 index 00000000..9cc9ffc7 --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x64/zttap300.inf @@ -0,0 +1,143 @@ +; +; ZeroTier One Virtual Network Port NDIS6 Driver +; +; Based on the OpenVPN tap-windows6 driver version 9.21.1 git +; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3. +; See: https://github.com/OpenVPN/tap-windows6 +; +; Modified by ZeroTier, Inc. - https://www.zerotier.com/ +; +; (1) Comment out 'tun' functionality and related features such as DHCP +; emulation, since we don't use any of that. Just want straight 'tap'. +; (2) Added custom IOCTL to enumerate L2 multicast memberships. +; (3) Increase maximum number of multicast memberships to 128. +; (4) Set default and max device MTU to 2800. +; (5) Rename/rebrand driver as ZeroTier network port driver. +; +; Original copyright below. Modifications released under GPLv2 as well. +; +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** +; + +[Version] +Signature = "$Windows NT$" +CatalogFile = zttap300.cat +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %Provider% +Class = Net +DriverVer=04/25/2015,6.2.9200.20557 + +[Strings] +DeviceDescription = "ZeroTier One Virtual Port" +Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. + +; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! +[Manufacturer] +%Provider%=zttap300,NTamd64 + +[zttap300] +%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated +%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy + +[zttap300.NTamd64] +%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated +%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy + +;----------------- Characteristics ------------ +; NCF_PHYSICAL = 0x04 +; NCF_VIRTUAL = 0x01 +; NCF_SOFTWARE_ENUMERATED = 0x02 +; NCF_HIDDEN = 0x08 +; NCF_NO_SERVICE = 0x10 +; NCF_HAS_UI = 0x80 +;----------------- Characteristics ------------ +[zttap300.ndi] +CopyFiles = zttap300.driver, zttap300.files +AddReg = zttap300.reg +AddReg = zttap300.params.reg +Characteristics = 0x81 +*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType = 0x0 ; NdisMedium802_3 +*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[zttap300.ndi.Services] +AddService = zttap300, 2, zttap300.service + +[zttap300.reg] +HKR, Ndi, Service, 0, "zttap300" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows. +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" +HKR, , Manufacturer, 0, "%Provider%" +HKR, , ProductName, 0, "%DeviceDescription%" + +[zttap300.params.reg] +HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" +HKR, Ndi\params\MTU, Type, 0, "int" +HKR, Ndi\params\MTU, Default, 0, "2800" +HKR, Ndi\params\MTU, Optional, 0, "0" +HKR, Ndi\params\MTU, Min, 0, "100" +HKR, Ndi\params\MTU, Max, 0, "2800" +HKR, Ndi\params\MTU, Step, 0, "1" +HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" +HKR, Ndi\params\MediaStatus, Type, 0, "enum" +HKR, Ndi\params\MediaStatus, Default, 0, "0" +HKR, Ndi\params\MediaStatus, Optional, 0, "0" +HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" +HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" +HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" +HKR, Ndi\params\MAC, Type, 0, "edit" +HKR, Ndi\params\MAC, Optional, 0, "1" +HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" +HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" +HKR, Ndi\params\AllowNonAdmin, Default, 0, "0" +HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" +HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" +HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" + +;---------- Service Type ------------- +; SERVICE_KERNEL_DRIVER = 0x01 +; SERVICE_WIN32_OWN_PROCESS = 0x10 +;---------- Service Type ------------- + +;---------- Start Mode --------------- +; SERVICE_BOOT_START = 0x0 +; SERVICE_SYSTEM_START = 0x1 +; SERVICE_AUTO_START = 0x2 +; SERVICE_DEMAND_START = 0x3 +; SERVICE_DISABLED = 0x4 +;---------- Start Mode --------------- + +[zttap300.service] +DisplayName = %DeviceDescription% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +LoadOrderGroup = NDIS +ServiceBinary = %12%\zttap300.sys + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +[SourceDisksNames] +1 = %DeviceDescription%, zttap300.sys + +[SourceDisksFiles] +zttap300.sys = 1 + +[DestinationDirs] +zttap300.files = 11 +zttap300.driver = 12 + +[zttap300.files] +; + +[zttap300.driver] +zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.sys b/ext/bin/tap-windows-ndis6/x64/zttap300.sys Binary files differnew file mode 100644 index 00000000..060916f9 --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x64/zttap300.sys diff --git a/ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll Binary files differnew file mode 100644 index 00000000..e943ea45 --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.cat b/ext/bin/tap-windows-ndis6/x86/zttap300.cat Binary files differnew file mode 100644 index 00000000..d899961e --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x86/zttap300.cat diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.inf b/ext/bin/tap-windows-ndis6/x86/zttap300.inf new file mode 100644 index 00000000..5f46dbfd --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x86/zttap300.inf @@ -0,0 +1,139 @@ +; +; ZeroTier One Virtual Network Port NDIS6 Driver +; +; Based on the OpenVPN tap-windows6 driver version 9.21.1 git +; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3. +; See: https://github.com/OpenVPN/tap-windows6 +; +; Modified by ZeroTier, Inc. - https://www.zerotier.com/ +; +; (1) Comment out 'tun' functionality and related features such as DHCP +; emulation, since we don't use any of that. Just want straight 'tap'. +; (2) Added custom IOCTL to enumerate L2 multicast memberships. +; (3) Increase maximum number of multicast memberships to 128. +; (4) Set default and max device MTU to 2800. +; (5) Rename/rebrand driver as ZeroTier network port driver. +; +; Original copyright below. Modifications released under GPLv2 as well. +; +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** +; + +[Version] +Signature = "$Windows NT$" +CatalogFile = zttap300.cat +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %Provider% +Class = Net +DriverVer=04/25/2015,6.2.9200.20557 + +[Strings] +DeviceDescription = "ZeroTier One Virtual Port" +Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. + +; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! +[Manufacturer] +%Provider%=zttap300 + +[zttap300] +%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated +%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy + +;----------------- Characteristics ------------ +; NCF_PHYSICAL = 0x04 +; NCF_VIRTUAL = 0x01 +; NCF_SOFTWARE_ENUMERATED = 0x02 +; NCF_HIDDEN = 0x08 +; NCF_NO_SERVICE = 0x10 +; NCF_HAS_UI = 0x80 +;----------------- Characteristics ------------ +[zttap300.ndi] +CopyFiles = zttap300.driver, zttap300.files +AddReg = zttap300.reg +AddReg = zttap300.params.reg +Characteristics = 0x81 +*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType = 0x0 ; NdisMedium802_3 +*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[zttap300.ndi.Services] +AddService = zttap300, 2, zttap300.service + +[zttap300.reg] +HKR, Ndi, Service, 0, "zttap300" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows. +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" +HKR, , Manufacturer, 0, "%Provider%" +HKR, , ProductName, 0, "%DeviceDescription%" + +[zttap300.params.reg] +HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" +HKR, Ndi\params\MTU, Type, 0, "int" +HKR, Ndi\params\MTU, Default, 0, "2800" +HKR, Ndi\params\MTU, Optional, 0, "0" +HKR, Ndi\params\MTU, Min, 0, "100" +HKR, Ndi\params\MTU, Max, 0, "2800" +HKR, Ndi\params\MTU, Step, 0, "1" +HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" +HKR, Ndi\params\MediaStatus, Type, 0, "enum" +HKR, Ndi\params\MediaStatus, Default, 0, "0" +HKR, Ndi\params\MediaStatus, Optional, 0, "0" +HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" +HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" +HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" +HKR, Ndi\params\MAC, Type, 0, "edit" +HKR, Ndi\params\MAC, Optional, 0, "1" +HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" +HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" +HKR, Ndi\params\AllowNonAdmin, Default, 0, "0" +HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" +HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" +HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" + +;---------- Service Type ------------- +; SERVICE_KERNEL_DRIVER = 0x01 +; SERVICE_WIN32_OWN_PROCESS = 0x10 +;---------- Service Type ------------- + +;---------- Start Mode --------------- +; SERVICE_BOOT_START = 0x0 +; SERVICE_SYSTEM_START = 0x1 +; SERVICE_AUTO_START = 0x2 +; SERVICE_DEMAND_START = 0x3 +; SERVICE_DISABLED = 0x4 +;---------- Start Mode --------------- + +[zttap300.service] +DisplayName = %DeviceDescription% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +LoadOrderGroup = NDIS +ServiceBinary = %12%\zttap300.sys + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +[SourceDisksNames] +1 = %DeviceDescription%, zttap300.sys + +[SourceDisksFiles] +zttap300.sys = 1 + +[DestinationDirs] +zttap300.files = 11 +zttap300.driver = 12 + +[zttap300.files] +; + +[zttap300.driver] +zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.sys b/ext/bin/tap-windows-ndis6/x86/zttap300.sys Binary files differnew file mode 100644 index 00000000..29933e3e --- /dev/null +++ b/ext/bin/tap-windows-ndis6/x86/zttap300.sys diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index a0999b3d..220516ab 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -72,20 +72,21 @@ public: #ifdef _WIN64 is64Bit = TRUE; devcon = "\\devcon_x64.exe"; - tapDriver = "\\tap-windows\\x64\\zttap200.inf"; + tapDriverNdis5 = "\\tap-windows\\x64\\zttap200.inf"; + tapDriverNdis6 = "\\tap-windows\\x64\\zttap300.inf"; #else is64Bit = FALSE; IsWow64Process(GetCurrentProcess(),&is64Bit); devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); - tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); + tapDriverNdis5 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); + tapDriverNdis6 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap300.inf" : "\\tap-windows\\x86\\zttap300.inf"); #endif } - BOOL is64Bit; - std::string devcon; - std::string tapDriver; + const char *devcon; + const char *tapDriverNdis5; + const char *tapDriverNdis6; }; - static const WindowsEthernetTapEnv WINENV; } // anonymous namespace @@ -123,6 +124,16 @@ WindowsEthernetTap::WindowsEthernetTap( Mutex::Lock _l(_systemTapInitLock); + std::string tapDriverPath(_pathToHelpers + WINENV.tapDriverNdis6); + const char *tapDriverName = "zttap300"; + if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) { + tapDriverPath = _pathToHelpers + WINENV.tapDriverNdis5; + tapDriverName = "zttap200"; + if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) { + throw std::runtime_error("no tap driver available: cannot find zttap300.inf (NDIS6) or zttap200.inf (NDIS5) under home path"); + } + } + HKEY nwAdapters; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) throw std::runtime_error("unable to open registry key for network adapter enumeration"); @@ -198,7 +209,7 @@ WindowsEthernetTap::WindowsEthernetTap( PROCESS_INFORMATION processInfo; memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + _pathToHelpers + WINENV.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + tapDriverPath + "\" " + tapDriverName).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { RegCloseKey(nwAdapters); if (devconLog != INVALID_HANDLE_VALUE) CloseHandle(devconLog); diff --git a/windows/TapDriver6/TapDriver6.vcxproj b/windows/TapDriver6/TapDriver6.vcxproj new file mode 100644 index 00000000..ffe9441c --- /dev/null +++ b/windows/TapDriver6/TapDriver6.vcxproj @@ -0,0 +1,371 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Win8 Debug|Win32"> + <Configuration>Win8 Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win8 Release|Win32"> + <Configuration>Win8 Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win7 Debug|Win32"> + <Configuration>Win7 Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win7 Release|Win32"> + <Configuration>Win7 Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Vista Debug|Win32"> + <Configuration>Vista Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Vista Release|Win32"> + <Configuration>Vista Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win8 Debug|x64"> + <Configuration>Win8 Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win8 Release|x64"> + <Configuration>Win8 Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win7 Debug|x64"> + <Configuration>Win7 Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Win7 Release|x64"> + <Configuration>Win7 Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Vista Debug|x64"> + <Configuration>Vista Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Vista Release|x64"> + <Configuration>Vista Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}</ProjectGuid> + <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion> + <Configuration>Win8 Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + </PropertyGroup> + <PropertyGroup Label="Globals"> + <RootNamespace>TapDriver6</RootNamespace> + <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath> + </PropertyGroup> + <PropertyGroup Label="PropertySheets"> + <PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration"> + <TargetVersion>Windows8</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration"> + <TargetVersion>Windows8</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'" Label="Configuration"> + <TargetVersion>Windows7</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'" Label="Configuration"> + <TargetVersion>Windows7</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'" Label="Configuration"> + <TargetVersion>Vista</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'" Label="Configuration"> + <TargetVersion>Vista</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration"> + <TargetVersion>Windows8</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration"> + <TargetVersion>Windows8</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'" Label="Configuration"> + <TargetVersion>Windows7</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'" Label="Configuration"> + <TargetVersion>Windows7</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'" Label="Configuration"> + <TargetVersion>Vista</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'" Label="Configuration"> + <TargetVersion>Vista</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'"> + <TargetName>zttap300</TargetName> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <WppEnabled>false</WppEnabled> + <WppScanConfigurationData Condition="'%(ClCompile. ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData> + <WppKernelMode>false</WppKernelMode> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</WppMinimalRebuildFromTracking> + <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</WppMinimalRebuildFromTracking> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Level1</WarningLevel> + <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Level1</WarningLevel> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Default</CompileAs> + <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Default</CompileAs> + </ClCompile> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Link> + <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</SpecifyDriverVerDirectiveDate> + </Inf> + <Inf> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</SpecifyDriverVerDirectiveDate> + </Inf> + </ItemDefinitionGroup> + <ItemGroup> + <FilesToPackage Include="$(TargetPath)" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="adapter.c" /> + <ClCompile Include="device.c" /> + <ClCompile Include="error.c" /> + <ClCompile Include="macinfo.c" /> + <ClCompile Include="mem.c" /> + <ClCompile Include="oidrequest.c" /> + <ClCompile Include="rxpath.c" /> + <ClCompile Include="tapdrvr.c" /> + <ClCompile Include="txpath.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="adapter.h" /> + <ClInclude Include="config.h" /> + <ClInclude Include="constants.h" /> + <ClInclude Include="device.h" /> + <ClInclude Include="endian.h" /> + <ClInclude Include="error.h" /> + <ClInclude Include="hexdump.h" /> + <ClInclude Include="lock.h" /> + <ClInclude Include="macinfo.h" /> + <ClInclude Include="mem.h" /> + <ClInclude Include="proto.h" /> + <ClInclude Include="prototypes.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="tap-windows.h" /> + <ClInclude Include="tap.h" /> + <ClInclude Include="types.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="resource.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Include="zttap300.inf"> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">3.00.00.0</TimeStamp> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</SpecifyDriverVerDirectiveVersion> + <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</SpecifyDriverVerDirectiveVersion> + <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">3.00.00.0</TimeStamp> + </Inf> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/windows/TapDriver6/TapDriver6.vcxproj.filters b/windows/TapDriver6/TapDriver6.vcxproj.filters new file mode 100644 index 00000000..14cbbde0 --- /dev/null +++ b/windows/TapDriver6/TapDriver6.vcxproj.filters @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Driver Files"> + <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="adapter.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="error.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="macinfo.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="mem.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="oidrequest.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="rxpath.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="tapdrvr.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="txpath.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="adapter.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="constants.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="device.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="endian.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="error.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="hexdump.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="lock.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="macinfo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="mem.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="proto.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="prototypes.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="tap.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="tap-windows.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="types.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="resource.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <Inf Include="zttap300.inf"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/windows/TapDriver6/adapter.c b/windows/TapDriver6/adapter.c new file mode 100644 index 00000000..7ce4b310 --- /dev/null +++ b/windows/TapDriver6/adapter.c @@ -0,0 +1,1716 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +NDIS_OID TAPSupportedOids[] = +{ + OID_GEN_HARDWARE_STATUS, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_DRIVER_VERSION, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_STATISTICS, +#ifdef IMPLEMENT_OPTIONAL_OIDS + OID_GEN_TRANSMIT_QUEUE_LENGTH, // Optional +#endif // IMPLEMENT_OPTIONAL_OIDS + OID_GEN_LINK_PARAMETERS, + OID_GEN_INTERRUPT_MODERATION, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, +#ifdef IMPLEMENT_OPTIONAL_OIDS + OID_802_3_XMIT_DEFERRED, // Optional + OID_802_3_XMIT_MAX_COLLISIONS, // Optional + OID_802_3_RCV_OVERRUN, // Optional + OID_802_3_XMIT_UNDERRUN, // Optional + OID_802_3_XMIT_HEARTBEAT_FAILURE, // Optional + OID_802_3_XMIT_TIMES_CRS_LOST, // Optional + OID_802_3_XMIT_LATE_COLLISIONS, // Optional + OID_PNP_CAPABILITIES, // Optional +#endif // IMPLEMENT_OPTIONAL_OIDS +}; + +//====================================================================== +// TAP NDIS 6 Miniport Callbacks +//====================================================================== + +// Returns with reference count initialized to one. +PTAP_ADAPTER_CONTEXT +tapAdapterContextAllocate( + __in NDIS_HANDLE MiniportAdapterHandle +) +{ + PTAP_ADAPTER_CONTEXT adapter = NULL; + + adapter = (PTAP_ADAPTER_CONTEXT )NdisAllocateMemoryWithTagPriority( + GlobalData.NdisDriverHandle, + sizeof(TAP_ADAPTER_CONTEXT), + TAP_ADAPTER_TAG, + NormalPoolPriority + ); + + if(adapter) + { + NET_BUFFER_LIST_POOL_PARAMETERS nblPoolParameters = {0}; + + NdisZeroMemory(adapter,sizeof(TAP_ADAPTER_CONTEXT)); + + adapter->MiniportAdapterHandle = MiniportAdapterHandle; + + // Initialize cancel-safe IRP queue + tapIrpCsqInitialize(&adapter->PendingReadIrpQueue); + + // Initialize TAP send packet queue. + tapPacketQueueInitialize(&adapter->SendPacketQueue); + + // Allocate the adapter lock. + NdisAllocateSpinLock(&adapter->AdapterLock); + + // NBL pool for making TAP receive indications. + NdisZeroMemory(&nblPoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS)); + + // Initialize event used to determine when all receive NBLs have been returned. + NdisInitializeEvent(&adapter->ReceiveNblInFlightCountZeroEvent); + + nblPoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + nblPoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; + nblPoolParameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; + nblPoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT; + nblPoolParameters.ContextSize = 0; + //nblPoolParameters.ContextSize = sizeof(RX_NETBUFLIST_RSVD); + nblPoolParameters.fAllocateNetBuffer = TRUE; + nblPoolParameters.PoolTag = TAP_RX_NBL_TAG; + +#pragma warning( suppress : 28197 ) + adapter->ReceiveNblPool = NdisAllocateNetBufferListPool( + adapter->MiniportAdapterHandle, + &nblPoolParameters); + + if (adapter->ReceiveNblPool == NULL) + { + DEBUGP (("[TAP] Couldn't allocate adapter receive NBL pool\n")); + NdisFreeMemory(adapter,0,0); + } + + // Add initial reference. Normally removed in AdapterHalt. + adapter->RefCount = 1; + + // Safe for multiple removes. + NdisInitializeListHead(&adapter->AdapterListLink); + + // + // The miniport adapter is initially powered up + // + adapter->CurrentPowerState = NdisDeviceStateD0; + } + + return adapter; +} + +VOID +tapReadPermanentAddress( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in NDIS_HANDLE ConfigurationHandle, + __out MACADDR PermanentAddress + ) +{ + NDIS_STATUS status; + NDIS_CONFIGURATION_PARAMETER *configParameter; + NDIS_STRING macKey = NDIS_STRING_CONST("MAC"); + ANSI_STRING macString; + BOOLEAN macFromRegistry = FALSE; + + // Read MAC parameter from registry. + NdisReadConfiguration( + &status, + &configParameter, + ConfigurationHandle, + &macKey, + NdisParameterString + ); + + if (status == NDIS_STATUS_SUCCESS) + { + if( (configParameter->ParameterType == NdisParameterString) + && (configParameter->ParameterData.StringData.Length >= 12) + ) + { + if (RtlUnicodeStringToAnsiString( + &macString, + &configParameter->ParameterData.StringData, + TRUE) == STATUS_SUCCESS + ) + { + macFromRegistry = ParseMAC (PermanentAddress, macString.Buffer); + RtlFreeAnsiString (&macString); + } + } + } + + if(!macFromRegistry) + { + // + // There is no (valid) address stashed in the registry parameter. + // + // Make up a dummy mac address based on the ANSI representation of the + // NetCfgInstanceId GUID. + // + GenerateRandomMac(PermanentAddress, MINIPORT_INSTANCE_ID(Adapter)); + } +} + +NDIS_STATUS +tapReadConfiguration( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + NDIS_CONFIGURATION_OBJECT configObject; + NDIS_HANDLE configHandle; + + DEBUGP (("[TAP] --> tapReadConfiguration\n")); + + // + // Setup defaults in case configuration cannot be opened. + // + Adapter->MtuSize = ETHERNET_MTU; + Adapter->MediaStateAlwaysConnected = FALSE; + Adapter->LogicalMediaState = FALSE; + Adapter->AllowNonAdmin = FALSE; + // + // Open the registry for this adapter to read advanced + // configuration parameters stored by the INF file. + // + NdisZeroMemory(&configObject, sizeof(configObject)); + + {C_ASSERT(sizeof(configObject) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1);} + configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; + configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1; + configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; + + configObject.NdisHandle = Adapter->MiniportAdapterHandle; + configObject.Flags = 0; + + status = NdisOpenConfigurationEx( + &configObject, + &configHandle + ); + + // Read on the opened configuration handle. + if(status == NDIS_STATUS_SUCCESS) + { + NDIS_CONFIGURATION_PARAMETER *configParameter; + NDIS_STRING mkey = NDIS_STRING_CONST("NetCfgInstanceId"); + + // + // Read NetCfgInstanceId from the registry. + // ------------------------------------ + // NetCfgInstanceId is required to create device and associated + // symbolic link for the adapter device. + // + // NetCfgInstanceId is a GUID string provided by NDIS that identifies + // the adapter instance. An example is: + // + // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} + // + // Other names are derived from NetCfgInstanceId. For example, MiniportName: + // + // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} + // + NdisReadConfiguration ( + &status, + &configParameter, + configHandle, + &mkey, + NdisParameterString + ); + + if (status == NDIS_STATUS_SUCCESS) + { + if (configParameter->ParameterType == NdisParameterString) + { + DEBUGP (("[TAP] NdisReadConfiguration (NetCfgInstanceId=%wZ)\n", + &configParameter->ParameterData.StringData )); + + // Save NetCfgInstanceId as UNICODE_STRING. + Adapter->NetCfgInstanceId.Length = Adapter->NetCfgInstanceId.MaximumLength + = configParameter->ParameterData.StringData.Length; + + Adapter->NetCfgInstanceId.Buffer = Adapter->NetCfgInstanceIdBuffer; + + NdisMoveMemory( + Adapter->NetCfgInstanceId.Buffer, + configParameter->ParameterData.StringData.Buffer, + Adapter->NetCfgInstanceId.Length + ); + + // Save NetCfgInstanceId as ANSI_STRING as well. + if (RtlUnicodeStringToAnsiString ( + &Adapter->NetCfgInstanceIdAnsi, + &configParameter->ParameterData.StringData, + TRUE) != STATUS_SUCCESS + ) + { + DEBUGP (("[TAP] NetCfgInstanceId ANSI name conversion failed\n")); + status = NDIS_STATUS_RESOURCES; + } + } + else + { + DEBUGP (("[TAP] NetCfgInstanceId has invalid type\n")); + status = NDIS_STATUS_INVALID_DATA; + } + } + else + { + DEBUGP (("[TAP] NetCfgInstanceId failed\n")); + status = NDIS_STATUS_INVALID_DATA; + } + + if (status == NDIS_STATUS_SUCCESS) + { + NDIS_STATUS localStatus; // Use default if these fail. + NDIS_CONFIGURATION_PARAMETER *configParameter; + NDIS_STRING mtuKey = NDIS_STRING_CONST("MTU"); + NDIS_STRING mediaStatusKey = NDIS_STRING_CONST("MediaStatus"); +#if ENABLE_NONADMIN + NDIS_STRING allowNonAdminKey = NDIS_STRING_CONST("AllowNonAdmin"); +#endif + + // Read MTU from the registry. + NdisReadConfiguration ( + &localStatus, + &configParameter, + configHandle, + &mtuKey, + NdisParameterInteger + ); + + if (localStatus == NDIS_STATUS_SUCCESS) + { + if (configParameter->ParameterType == NdisParameterInteger) + { + int mtu = configParameter->ParameterData.IntegerData; + + if(mtu == 0) + { + mtu = ETHERNET_MTU; + } + + // Sanity check + if (mtu < MINIMUM_MTU) + { + mtu = MINIMUM_MTU; + } + else if (mtu > MAXIMUM_MTU) + { + mtu = MAXIMUM_MTU; + } + + Adapter->MtuSize = mtu; + } + } + + DEBUGP (("[%s] Using MTU %d\n", + MINIPORT_INSTANCE_ID (Adapter), + Adapter->MtuSize + )); + + // Read MediaStatus setting from registry. + NdisReadConfiguration ( + &localStatus, + &configParameter, + configHandle, + &mediaStatusKey, + NdisParameterInteger + ); + + if (localStatus == NDIS_STATUS_SUCCESS) + { + if (configParameter->ParameterType == NdisParameterInteger) + { + if(configParameter->ParameterData.IntegerData == 0) + { + // Connect state is appplication controlled. + DEBUGP(("[%s] Initial MediaConnectState: Application Controlled\n", + MINIPORT_INSTANCE_ID (Adapter))); + + Adapter->MediaStateAlwaysConnected = FALSE; + Adapter->LogicalMediaState = FALSE; + } + else + { + // Connect state is always connected. + DEBUGP(("[%s] Initial MediaConnectState: Always Connected\n", + MINIPORT_INSTANCE_ID (Adapter))); + + Adapter->MediaStateAlwaysConnected = TRUE; + Adapter->LogicalMediaState = TRUE; + } + } + } + + // Read MAC PermanentAddress setting from registry. + tapReadPermanentAddress( + Adapter, + configHandle, + Adapter->PermanentAddress + ); + + DEBUGP (("[%s] Using MAC PermanentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + MINIPORT_INSTANCE_ID (Adapter), + Adapter->PermanentAddress[0], + Adapter->PermanentAddress[1], + Adapter->PermanentAddress[2], + Adapter->PermanentAddress[3], + Adapter->PermanentAddress[4], + Adapter->PermanentAddress[5]) + ); + + // Now seed the current MAC address with the permanent address. + ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress); + + DEBUGP (("[%s] Using MAC CurrentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + MINIPORT_INSTANCE_ID (Adapter), + Adapter->CurrentAddress[0], + Adapter->CurrentAddress[1], + Adapter->CurrentAddress[2], + Adapter->CurrentAddress[3], + Adapter->CurrentAddress[4], + Adapter->CurrentAddress[5]) + ); + + // Read optional AllowNonAdmin setting from registry. +#if ENABLE_NONADMIN + NdisReadConfiguration ( + &localStatus, + &configParameter, + configHandle, + &allowNonAdminKey, + NdisParameterInteger + ); + + if (localStatus == NDIS_STATUS_SUCCESS) + { + if (configParameter->ParameterType == NdisParameterInteger) + { + Adapter->AllowNonAdmin = TRUE; + } + } +#endif + } + + // Close the configuration handle. + NdisCloseConfiguration(configHandle); + } + else + { + DEBUGP (("[TAP] Couldn't open adapter registry\n")); + } + + DEBUGP (("[TAP] <-- tapReadConfiguration; status = %8.8X\n",status)); + + return status; +} + +VOID +tapAdapterContextAddToGlobalList( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + LOCK_STATE lockState; + PLIST_ENTRY listEntry = &Adapter->AdapterListLink; + + // Acquire global adapter list lock. + NdisAcquireReadWriteLock( + &GlobalData.Lock, + TRUE, // Acquire for write + &lockState + ); + + // Adapter context should NOT be in any list. + ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) ); + + // Add reference to persist until after removal. + tapAdapterContextReference(Adapter); + + // Add the adapter context to the global list. + InsertTailList(&GlobalData.AdapterList,&Adapter->AdapterListLink); + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); +} + +VOID +tapAdapterContextRemoveFromGlobalList( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + LOCK_STATE lockState; + + // Acquire global adapter list lock. + NdisAcquireReadWriteLock( + &GlobalData.Lock, + TRUE, // Acquire for write + &lockState + ); + + // Remove the adapter context from the global list. + RemoveEntryList(&Adapter->AdapterListLink); + + // Safe for multiple removes. + NdisInitializeListHead(&Adapter->AdapterListLink); + + // Remove reference added in tapAdapterContextAddToGlobalList. + tapAdapterContextDereference(Adapter); + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); +} + +// Returns with added reference on adapter context. +PTAP_ADAPTER_CONTEXT +tapAdapterContextFromDeviceObject( + __in PDEVICE_OBJECT DeviceObject + ) +{ + LOCK_STATE lockState; + + // Acquire global adapter list lock. + NdisAcquireReadWriteLock( + &GlobalData.Lock, + FALSE, // Acquire for read + &lockState + ); + + if (!IsListEmpty(&GlobalData.AdapterList)) + { + PLIST_ENTRY entry = GlobalData.AdapterList.Flink; + PTAP_ADAPTER_CONTEXT adapter; + + while (entry != &GlobalData.AdapterList) + { + adapter = CONTAINING_RECORD(entry, TAP_ADAPTER_CONTEXT, AdapterListLink); + + // Match on DeviceObject + if(adapter->DeviceObject == DeviceObject ) + { + // Add reference to adapter context. + tapAdapterContextReference(adapter); + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); + + return adapter; + } + + // Move to next entry + entry = entry->Flink; + } + } + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState); + + return (PTAP_ADAPTER_CONTEXT )NULL; +} + +NDIS_STATUS +AdapterSetOptions( + __in NDIS_HANDLE NdisDriverHandle, + __in NDIS_HANDLE DriverContext + ) +/*++ +Routine Description: + + The MiniportSetOptions function registers optional handlers. For each + optional handler that should be registered, this function makes a call + to NdisSetOptionalHandlers. + + MiniportSetOptions runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + DriverContext The context handle + +Return Value: + + NDIS_STATUS_xxx code + +--*/ +{ + NDIS_STATUS status; + + DEBUGP (("[TAP] --> AdapterSetOptions\n")); + + // + // Set any optional handlers by filling out the appropriate struct and + // calling NdisSetOptionalHandlers here. + // + + status = NDIS_STATUS_SUCCESS; + + DEBUGP (("[TAP] <-- AdapterSetOptions; status = %8.8X\n",status)); + + return status; +} + +NDIS_STATUS +AdapterCreate( + __in NDIS_HANDLE MiniportAdapterHandle, + __in NDIS_HANDLE MiniportDriverContext, + __in PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters + ) +{ + PTAP_ADAPTER_CONTEXT adapter = NULL; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(MiniportDriverContext); + UNREFERENCED_PARAMETER(MiniportInitParameters); + + DEBUGP (("[TAP] --> AdapterCreate\n")); + + do + { + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES regAttributes = {0}; + NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES genAttributes = {0}; + NDIS_PNP_CAPABILITIES pnpCapabilities = {0}; + + // + // Allocate adapter context structure and initialize all the + // memory resources for sending and receiving packets. + // + // Returns with reference count initialized to one. + // + adapter = tapAdapterContextAllocate(MiniportAdapterHandle); + + if(adapter == NULL) + { + DEBUGP (("[TAP] Couldn't allocate adapter memory\n")); + status = NDIS_STATUS_RESOURCES; + break; + } + + // Enter the Initializing state. + DEBUGP (("[TAP] Miniport State: Initializing\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportInitializingState; + tapAdapterReleaseLock(adapter,FALSE); + + // + // First read adapter configuration from registry. + // ----------------------------------------------- + // Subsequent device registration will fail if NetCfgInstanceId + // has not been successfully read. + // + status = tapReadConfiguration(adapter); + + // + // Set the registration attributes. + // + {C_ASSERT(sizeof(regAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1);} + regAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; + regAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + regAttributes.Header.Revision = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + + regAttributes.MiniportAdapterContext = adapter; + regAttributes.AttributeFlags = TAP_ADAPTER_ATTRIBUTES_FLAGS; + + regAttributes.CheckForHangTimeInSeconds = TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS; + regAttributes.InterfaceType = TAP_INTERFACE_TYPE; + + //NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(TAP_ADAPTER_CONTEXT); + status = NdisMSetMiniportAttributes( + MiniportAdapterHandle, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)®Attributes + ); + + if (status != NDIS_STATUS_SUCCESS) + { + DEBUGP (("[TAP] NdisSetOptionalHandlers failed; Status 0x%08x\n",status)); + break; + } + + // + // Next, set the general attributes. + // + {C_ASSERT(sizeof(genAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1);} + genAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; + genAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + genAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + + // + // Specify the medium type that the NIC can support but not + // necessarily the medium type that the NIC currently uses. + // + genAttributes.MediaType = TAP_MEDIUM_TYPE; + + // + // Specifiy medium type that the NIC currently uses. + // + genAttributes.PhysicalMediumType = TAP_PHYSICAL_MEDIUM; + + // + // Specifiy the maximum network frame size, in bytes, that the NIC + // supports excluding the header. + // + genAttributes.MtuSize = TAP_FRAME_MAX_DATA_SIZE; + genAttributes.MaxXmitLinkSpeed = TAP_XMIT_SPEED; + genAttributes.XmitLinkSpeed = TAP_XMIT_SPEED; + genAttributes.MaxRcvLinkSpeed = TAP_RECV_SPEED; + genAttributes.RcvLinkSpeed = TAP_RECV_SPEED; + + if(adapter->MediaStateAlwaysConnected) + { + DEBUGP(("[%s] Initial MediaConnectState: Connected\n", + MINIPORT_INSTANCE_ID (adapter))); + + genAttributes.MediaConnectState = MediaConnectStateConnected; + } + else + { + DEBUGP(("[%s] Initial MediaConnectState: Disconnected\n", + MINIPORT_INSTANCE_ID (adapter))); + + genAttributes.MediaConnectState = MediaConnectStateDisconnected; + } + + genAttributes.MediaDuplexState = MediaDuplexStateFull; + + // + // The maximum number of bytes the NIC can provide as lookahead data. + // If that value is different from the size of the lookahead buffer + // supported by bound protocols, NDIS will call MiniportOidRequest to + // set the size of the lookahead buffer provided by the miniport driver + // to the minimum of the miniport driver and protocol(s) values. If the + // driver always indicates up full packets with + // NdisMIndicateReceiveNetBufferLists, it should set this value to the + // maximum total frame size, which excludes the header. + // + // Upper-layer drivers examine lookahead data to determine whether a + // packet that is associated with the lookahead data is intended for + // one or more of their clients. If the underlying driver supports + // multipacket receive indications, bound protocols are given full net + // packets on every indication. Consequently, this value is identical + // to that returned for OID_GEN_RECEIVE_BLOCK_SIZE. + // + genAttributes.LookaheadSize = TAP_MAX_LOOKAHEAD; + genAttributes.MacOptions = TAP_MAC_OPTIONS; + genAttributes.SupportedPacketFilters = TAP_SUPPORTED_FILTERS; + + // + // The maximum number of multicast addresses the NIC driver can manage. + // This list is global for all protocols bound to (or above) the NIC. + // Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from + // the NIC driver when attempting to set the multicast address list, + // even if the number of elements in the given list is less than the + // number originally returned for this query. + // + genAttributes.MaxMulticastListSize = TAP_MAX_MCAST_LIST; + genAttributes.MacAddressLength = MACADDR_SIZE; + + // + // Return the MAC address of the NIC burnt in the hardware. + // + ETH_COPY_NETWORK_ADDRESS(genAttributes.PermanentMacAddress, adapter->PermanentAddress); + + // + // Return the MAC address the NIC is currently programmed to use. Note + // that this address could be different from the permananent address as + // the user can override using registry. Read NdisReadNetworkAddress + // doc for more info. + // + ETH_COPY_NETWORK_ADDRESS(genAttributes.CurrentMacAddress, adapter->CurrentAddress); + + genAttributes.RecvScaleCapabilities = NULL; + genAttributes.AccessType = TAP_ACCESS_TYPE; + genAttributes.DirectionType = TAP_DIRECTION_TYPE; + genAttributes.ConnectionType = TAP_CONNECTION_TYPE; + genAttributes.IfType = TAP_IFTYPE; + genAttributes.IfConnectorPresent = TAP_HAS_PHYSICAL_CONNECTOR; + genAttributes.SupportedStatistics = TAP_SUPPORTED_STATISTICS; + genAttributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported; // IEEE 802.3 pause frames + genAttributes.DataBackFillSize = 0; + genAttributes.ContextBackFillSize = 0; + + // + // The SupportedOidList is an array of OIDs for objects that the + // underlying driver or its NIC supports. Objects include general, + // media-specific, and implementation-specific objects. NDIS forwards a + // subset of the returned list to protocols that make this query. That + // is, NDIS filters any supported statistics OIDs out of the list + // because protocols never make statistics queries. + // + genAttributes.SupportedOidList = TAPSupportedOids; + genAttributes.SupportedOidListLength = sizeof(TAPSupportedOids); + genAttributes.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED; + + // + // Set power management capabilities + // + NdisZeroMemory(&pnpCapabilities, sizeof(pnpCapabilities)); + pnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; + pnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; + genAttributes.PowerManagementCapabilities = &pnpCapabilities; + + status = NdisMSetMiniportAttributes( + MiniportAdapterHandle, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&genAttributes + ); + + if (status != NDIS_STATUS_SUCCESS) + { + DEBUGP (("[TAP] NdisMSetMiniportAttributes failed; Status 0x%08x\n",status)); + break; + } + + // + // Create the Win32 device I/O interface. + // + status = CreateTapDevice(adapter); + + if (status == NDIS_STATUS_SUCCESS) + { + // Add this adapter to the global adapter list. + tapAdapterContextAddToGlobalList(adapter); + } + else + { + DEBUGP (("[TAP] CreateTapDevice failed; Status 0x%08x\n",status)); + break; + } + } while(FALSE); + + if(status == NDIS_STATUS_SUCCESS) + { + // Enter the Paused state if initialization is complete. + DEBUGP (("[TAP] Miniport State: Paused\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportPausedState; + tapAdapterReleaseLock(adapter,FALSE); + } + else + { + if(adapter != NULL) + { + DEBUGP (("[TAP] Miniport State: Halted\n")); + + // + // Remove reference when adapter context was allocated + // --------------------------------------------------- + // This should result in freeing adapter context memory + // and assiciated resources. + // + tapAdapterContextDereference(adapter); + adapter = NULL; + } + } + + DEBUGP (("[TAP] <-- AdapterCreate; status = %8.8X\n",status)); + + return status; +} + +VOID +AdapterHalt( + __in NDIS_HANDLE MiniportAdapterContext, + __in NDIS_HALT_ACTION HaltAction + ) +/*++ + +Routine Description: + + Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE, + IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the PNP + manager. Here, the driver should free all the resources acquired in + MiniportInitialize and stop access to the hardware. NDIS will not submit + any further request once this handler is invoked. + + 1) Free and unmap all I/O resources. + 2) Disable interrupt and deregister interrupt handler. + 3) Deregister shutdown handler regsitered by + NdisMRegisterAdapterShutdownHandler . + 4) Cancel all queued up timer callbacks. + 5) Finally wait indefinitely for all the outstanding receive + packets indicated to the protocol to return. + + MiniportHalt runs at IRQL = PASSIVE_LEVEL. + + +Arguments: + + MiniportAdapterContext Pointer to the Adapter + HaltAction The reason for halting the adapter + +Return Value: + + None. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + + UNREFERENCED_PARAMETER(HaltAction); + + DEBUGP (("[TAP] --> AdapterHalt\n")); + + // Enter the Halted state. + DEBUGP (("[TAP] Miniport State: Halted\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportHaltedState; + tapAdapterReleaseLock(adapter,FALSE); + + // Remove this adapter from the global adapter list. + tapAdapterContextRemoveFromGlobalList(adapter); + + // BUGBUG!!! Call AdapterShutdownEx to do some of the work of stopping. + + // TODO!!! More... + + // + // Destroy the TAP Win32 device. + // + DestroyTapDevice(adapter); + + // + // Remove initial reference added in AdapterCreate. + // ------------------------------------------------ + // This should result in freeing adapter context memory + // and resources allocated in AdapterCreate. + // + tapAdapterContextDereference(adapter); + adapter = NULL; + + DEBUGP (("[TAP] <-- AdapterHalt\n")); +} + +VOID +tapWaitForReceiveNblInFlightCountZeroEvent( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + LONG nblCount; + + // + // Wait until higher-level protocol has returned all NBLs + // to the driver. + // + + // Add one NBL "bias" to insure allow event to be reset safely. + nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0 ); + NdisResetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); + + // + // Now remove the bias and wait for the ReceiveNblInFlightCountZeroEvent + // if the count returned is not zero. + // + nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount >= 0); + + if(nblCount) + { + LARGE_INTEGER startTime, currentTime; + + NdisGetSystemUpTimeEx(&startTime); + + for (;;) + { + BOOLEAN waitResult = NdisWaitEvent( + &Adapter->ReceiveNblInFlightCountZeroEvent, + TAP_WAIT_POLL_LOOP_TIMEOUT + ); + + NdisGetSystemUpTimeEx(¤tTime); + + if (waitResult) + { + break; + } + + DEBUGP (("[%s] Waiting for %d in-flight receive NBLs to be returned.\n", + MINIPORT_INSTANCE_ID (Adapter), + Adapter->ReceiveNblInFlightCount + )); + } + + DEBUGP (("[%s] Waited %d ms for all in-flight NBLs to be returned.\n", + MINIPORT_INSTANCE_ID (Adapter), + (currentTime.LowPart - startTime.LowPart) + )); + } +} + +NDIS_STATUS +AdapterPause( + __in NDIS_HANDLE MiniportAdapterContext, + __in PNDIS_MINIPORT_PAUSE_PARAMETERS PauseParameters + ) +/*++ + +Routine Description: + + When a miniport receives a pause request, it enters into a Pausing state. + The miniport should not indicate up any more network data. Any pending + send requests must be completed, and new requests must be rejected with + NDIS_STATUS_PAUSED. + + Once all sends have been completed and all recieve NBLs have returned to + the miniport, the miniport enters the Paused state. + + While paused, the miniport can still service interrupts from the hardware + (to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT + notifications). + + The miniport must continue to be able to handle status indications and OID + requests. MiniportPause is different from MiniportHalt because, in + general, the MiniportPause operation won't release any resources. + MiniportPause must not attempt to acquire any resources where allocation + can fail, since MiniportPause itself must not fail. + + + MiniportPause runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + MiniportAdapterContext Pointer to the Adapter + MiniportPauseParameters Additional information about the pause operation + +Return Value: + + If the miniport is able to immediately enter the Paused state, it should + return NDIS_STATUS_SUCCESS. + + If the miniport must wait for send completions or pending receive NBLs, it + should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the + miniport has entered the Paused state. + + No other return value is permitted. The pause operation must not fail. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(PauseParameters); + + DEBUGP (("[TAP] --> AdapterPause\n")); + + // Enter the Pausing state. + DEBUGP (("[TAP] Miniport State: Pausing\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportPausingState; + tapAdapterReleaseLock(adapter,FALSE); + + // + // Stop the flow of network data through the receive path + // ------------------------------------------------------ + // In the Pausing and Paused state tapAdapterSendAndReceiveReady + // will prevent new calls to NdisMIndicateReceiveNetBufferLists + // to indicate additional receive NBLs to the host. + // + // However, there may be some in-flight NBLs owned by the driver + // that have been indicated to the host but have not yet been + // returned. + // + // Wait here for all in-flight receive indications to be returned. + // + tapWaitForReceiveNblInFlightCountZeroEvent(adapter); + + // + // Stop the flow of network data through the send path + // --------------------------------------------------- + // The initial implementation of the NDIS 6 send path follows the + // NDIS 5 pattern. Under this approach every send packet is copied + // into a driver-owned TAP_PACKET structure and the NBL owned by + // higher-level protocol is immediatly completed. + // + // With this deep-copy approach the driver never claims ownership + // of any send NBL. + // + // A future implementation may queue send NBLs and thereby eliminate + // the need for the unnecessary allocation and deep copy of each packet. + // + // So, nothing to do here for the send path for now... + + status = NDIS_STATUS_SUCCESS; + + // Enter the Paused state. + DEBUGP (("[TAP] Miniport State: Paused\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportPausedState; + tapAdapterReleaseLock(adapter,FALSE); + + DEBUGP (("[TAP] <-- AdapterPause; status = %8.8X\n",status)); + + return status; +} + +NDIS_STATUS +AdapterRestart( + __in NDIS_HANDLE MiniportAdapterContext, + __in PNDIS_MINIPORT_RESTART_PARAMETERS RestartParameters + ) +/*++ + +Routine Description: + + When a miniport receives a restart request, it enters into a Restarting + state. The miniport may begin indicating received data (e.g., using + NdisMIndicateReceiveNetBufferLists), handling status indications, and + processing OID requests in the Restarting state. However, no sends will be + requested while the miniport is in the Restarting state. + + Once the miniport is ready to send data, it has entered the Running state. + The miniport informs NDIS that it is in the Running state by returning + NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function + has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete. + + + MiniportRestart runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + MiniportAdapterContext Pointer to the Adapter + RestartParameters Additional information about the restart operation + +Return Value: + + If the miniport is able to immediately enter the Running state, it should + return NDIS_STATUS_SUCCESS. + + If the miniport is still in the Restarting state, it should return + NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport + has entered the Running state. + + Other NDIS_STATUS codes indicate errors. If an error is encountered, the + miniport must return to the Paused state (i.e., stop indicating receives). + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(RestartParameters); + + DEBUGP (("[TAP] --> AdapterRestart\n")); + + // Enter the Restarting state. + DEBUGP (("[TAP] Miniport State: Restarting\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportRestartingState; + tapAdapterReleaseLock(adapter,FALSE); + + status = NDIS_STATUS_SUCCESS; + + if(status == NDIS_STATUS_SUCCESS) + { + // Enter the Running state. + DEBUGP (("[TAP] Miniport State: Running\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportRunning; + tapAdapterReleaseLock(adapter,FALSE); + } + else + { + // Enter the Paused state if restart failed. + DEBUGP (("[TAP] Miniport State: Paused\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportPausedState; + tapAdapterReleaseLock(adapter,FALSE); + } + + DEBUGP (("[TAP] <-- AdapterRestart; status = %8.8X\n",status)); + + return status; +} + +BOOLEAN +tapAdapterReadAndWriteReady( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +/*++ + +Routine Description: + + This routine determines whether the adapter device interface can + accept read and write operations. + +Arguments: + + Adapter Pointer to our adapter context + +Return Value: + + Returns TRUE if the adapter state allows it to queue IRPs passed to + the device read and write callbacks. +--*/ +{ + if(!Adapter->TapDeviceCreated) + { + // TAP device not created or is being destroyed. + return FALSE; + } + + if(Adapter->TapFileObject == NULL) + { + // TAP application file object not open. + return FALSE; + } + + if(!Adapter->TapFileIsOpen) + { + // TAP application file object may be closing. + return FALSE; + } + + if(!Adapter->LogicalMediaState) + { + // Don't handle read/write if media not connected. + return FALSE; + } + + if(Adapter->CurrentPowerState != NdisDeviceStateD0) + { + // Don't handle read/write if device is not fully powered. + return FALSE; + } + + return TRUE; +} + +NDIS_STATUS +tapAdapterSendAndReceiveReady( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +/*++ + +Routine Description: + + This routine determines whether the adapter NDIS send and receive + paths are ready. + + This routine examines various adapter state variables and returns + a value that indicates whether the adapter NDIS interfaces can + accept send packets or indicate receive packets. + + In normal operation the adapter may temporarily enter and then exit + a not-ready condition. In particular, the adapter becomes not-ready + when in the Pausing/Paused states, but may become ready again when + Restarted. + + Runs at IRQL <= DISPATCH_LEVEL + +Arguments: + + Adapter Pointer to our adapter context + +Return Value: + + Returns NDIS_STATUS_SUCCESS if the adapter state allows it to + accept send packets and indicate receive packets. + + Otherwise it returns a NDIS_STATUS value other than NDIS_STATUS_SUCCESS. + These status values can be used directly as the completion status for + packets that must be completed immediatly in the send path. +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + // + // Check various state variables to insure adapter is ready. + // + tapAdapterAcquireLock(Adapter,FALSE); + + if(!Adapter->LogicalMediaState) + { + status = NDIS_STATUS_MEDIA_DISCONNECTED; + } + else if(Adapter->CurrentPowerState != NdisDeviceStateD0) + { + status = NDIS_STATUS_LOW_POWER_STATE; + } + else if(Adapter->ResetInProgress) + { + status = NDIS_STATUS_RESET_IN_PROGRESS; + } + else + { + switch(Adapter->Locked.AdapterState) + { + case MiniportPausingState: + case MiniportPausedState: + status = NDIS_STATUS_PAUSED; + break; + + case MiniportHaltedState: + status = NDIS_STATUS_INVALID_STATE; + break; + + default: + status = NDIS_STATUS_SUCCESS; + break; + } + } + + tapAdapterReleaseLock(Adapter,FALSE); + + return status; +} + +BOOLEAN +AdapterCheckForHangEx( + __in NDIS_HANDLE MiniportAdapterContext + ) +/*++ + +Routine Description: + + The MiniportCheckForHangEx handler is called to report the state of the + NIC, or to monitor the responsiveness of an underlying device driver. + This is an optional function. If this handler is not specified, NDIS + judges the driver unresponsive when the driver holds + MiniportQueryInformation or MiniportSetInformation requests for a + time-out interval (deafult 4 sec), and then calls the driver's + MiniportReset function. A NIC driver's MiniportInitialize function can + extend NDIS's time-out interval by calling NdisMSetAttributesEx to + avoid unnecessary resets. + + MiniportCheckForHangEx runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + + MiniportAdapterContext Pointer to our adapter + +Return Value: + + TRUE NDIS calls the driver's MiniportReset function. + FALSE Everything is fine + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + + //DEBUGP (("[TAP] --> AdapterCheckForHangEx\n")); + + //DEBUGP (("[TAP] <-- AdapterCheckForHangEx; status = FALSE\n")); + + return FALSE; // Everything is fine +} + +NDIS_STATUS +AdapterReset( + __in NDIS_HANDLE MiniportAdapterContext, + __out PBOOLEAN AddressingReset + ) +/*++ + +Routine Description: + + MiniportResetEx is a required to issue a hardware reset to the NIC + and/or to reset the driver's software state. + + 1) The miniport driver can optionally complete any pending + OID requests. NDIS will submit no further OID requests + to the miniport driver for the NIC being reset until + the reset operation has finished. After the reset, + NDIS will resubmit to the miniport driver any OID requests + that were pending but not completed by the miniport driver + before the reset. + + 2) A deserialized miniport driver must complete any pending send + operations. NDIS will not requeue pending send packets for + a deserialized driver since NDIS does not maintain the send + queue for such a driver. + + 3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must + complete the original request subsequently with a call to + NdisMResetComplete. + + MiniportReset runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + +AddressingReset - If multicast or functional addressing information + or the lookahead size, is changed by a reset, + MiniportReset must set the variable at AddressingReset + to TRUE before it returns control. This causes NDIS to + call the MiniportSetInformation function to restore + the information. + +MiniportAdapterContext - Pointer to our adapter + +Return Value: + + NDIS_STATUS + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(MiniportAdapterContext); + UNREFERENCED_PARAMETER(AddressingReset); + + DEBUGP (("[TAP] --> AdapterReset\n")); + + // Indicate that adapter reset is in progress. + adapter->ResetInProgress = TRUE; + + // See note above... + *AddressingReset = FALSE; + + // BUGBUG!!! TODO!!! Lots of work here... + + // Indicate that adapter reset has completed. + adapter->ResetInProgress = FALSE; + + status = NDIS_STATUS_SUCCESS; + + DEBUGP (("[TAP] <-- AdapterReset; status = %8.8X\n",status)); + + return status; +} + +VOID +AdapterDevicePnpEventNotify( + __in NDIS_HANDLE MiniportAdapterContext, + __in PNET_DEVICE_PNP_EVENT NetDevicePnPEvent + ) +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + + DEBUGP (("[TAP] --> AdapterDevicePnpEventNotify\n")); + +/* + switch (NetDevicePnPEvent->DevicePnPEvent) + { + case NdisDevicePnPEventSurpriseRemoved: + // + // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL. + // NDIS calls MiniportHalt function after this call returns. + // + MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED); + DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventSurpriseRemoved\n", Adapter); + break; + + case NdisDevicePnPEventPowerProfileChanged: + // + // After initializing a miniport driver and after miniport driver + // receives an OID_PNP_SET_POWER notification that specifies + // a device power state of NdisDeviceStateD0 (the powered-on state), + // NDIS calls the miniport's MiniportPnPEventNotify function with + // PnPEvent set to NdisDevicePnPEventPowerProfileChanged. + // + DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventPowerProfileChanged\n", Adapter); + + if (NetDevicePnPEvent->InformationBufferLength == sizeof(ULONG)) + { + ULONG NdisPowerProfile = *((PULONG)NetDevicePnPEvent->InformationBuffer); + + if (NdisPowerProfile == NdisPowerProfileBattery) + { + DEBUGP(MP_INFO, "[%p] The host system is running on battery power\n", Adapter); + } + if (NdisPowerProfile == NdisPowerProfileAcOnLine) + { + DEBUGP(MP_INFO, "[%p] The host system is running on AC power\n", Adapter); + } + } + break; + + default: + DEBUGP(MP_ERROR, "[%p] MPDevicePnpEventNotify: unknown PnP event 0x%x\n", Adapter, NetDevicePnPEvent->DevicePnPEvent); + } +*/ + DEBUGP (("[TAP] <-- AdapterDevicePnpEventNotify\n")); +} + +VOID +AdapterShutdownEx( + __in NDIS_HANDLE MiniportAdapterContext, + __in NDIS_SHUTDOWN_ACTION ShutdownAction + ) +/*++ + +Routine Description: + + The MiniportShutdownEx handler restores hardware to its initial state when + the system is shut down, whether by the user or because an unrecoverable + system error occurred. This is to ensure that the NIC is in a known + state and ready to be reinitialized when the machine is rebooted after + a system shutdown occurs for any reason, including a crash dump. + + Here just disable the interrupt and stop the DMA engine. Do not free + memory resources or wait for any packet transfers to complete. Do not call + into NDIS at this time. + + This can be called at aribitrary IRQL, including in the context of a + bugcheck. + +Arguments: + + MiniportAdapterContext Pointer to our adapter + ShutdownAction The reason why NDIS called the shutdown function + +Return Value: + + None. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + + UNREFERENCED_PARAMETER(ShutdownAction); + UNREFERENCED_PARAMETER(MiniportAdapterContext); + + DEBUGP (("[TAP] --> AdapterShutdownEx\n")); + + // Enter the Shutdown state. + DEBUGP (("[TAP] Miniport State: Shutdown\n")); + + tapAdapterAcquireLock(adapter,FALSE); + adapter->Locked.AdapterState = MiniportShutdownState; + tapAdapterReleaseLock(adapter,FALSE); + + // + // BUGBUG!!! FlushIrpQueues??? + // + + DEBUGP (("[TAP] <-- AdapterShutdownEx\n")); +} + + +// Free adapter context memory and associated resources. +VOID +tapAdapterContextFree( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + PLIST_ENTRY listEntry = &Adapter->AdapterListLink; + + DEBUGP (("[TAP] --> tapAdapterContextFree\n")); + + // Adapter context should already be removed. + ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) ); + + // Insure that adapter context has been removed from global adapter list. + RemoveEntryList(&Adapter->AdapterListLink); + + // Free the adapter lock. + NdisFreeSpinLock(&Adapter->AdapterLock); + + // Free the ANSI NetCfgInstanceId buffer. + if(Adapter->NetCfgInstanceIdAnsi.Buffer != NULL) + { + RtlFreeAnsiString(&Adapter->NetCfgInstanceIdAnsi); + } + + Adapter->NetCfgInstanceIdAnsi.Buffer = NULL; + + // Free the receive NBL pool. + if(Adapter->ReceiveNblPool != NULL ) + { + NdisFreeNetBufferListPool(Adapter->ReceiveNblPool); + } + + Adapter->ReceiveNblPool = NULL; + + NdisFreeMemory(Adapter,0,0); + + DEBUGP (("[TAP] <-- tapAdapterContextFree\n")); +} +ULONG +tapGetNetBufferFrameType( + __in PNET_BUFFER NetBuffer + ) +/*++ + +Routine Description: + + Reads the network frame's destination address to determine the type + (broadcast, multicast, etc) + + Runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + + NetBuffer The NB to examine + +Return Value: + + NDIS_PACKET_TYPE_BROADCAST + NDIS_PACKET_TYPE_MULTICAST + NDIS_PACKET_TYPE_DIRECTED + +--*/ +{ + PETH_HEADER ethernetHeader; + + ethernetHeader = (PETH_HEADER )NdisGetDataBuffer( + NetBuffer, + sizeof(ETH_HEADER), + NULL, + 1, + 0 + ); + + ASSERT(ethernetHeader); + + if (ETH_IS_BROADCAST(ethernetHeader->dest)) + { + return NDIS_PACKET_TYPE_BROADCAST; + } + else if(ETH_IS_MULTICAST(ethernetHeader->dest)) + { + return NDIS_PACKET_TYPE_MULTICAST; + } + else + { + return NDIS_PACKET_TYPE_DIRECTED; + } + +} + +ULONG +tapGetNetBufferCountsFromNetBufferList( + __in PNET_BUFFER_LIST NetBufferList, + __inout_opt PULONG TotalByteCount // Of all linked NBs + ) +/*++ + +Routine Description: + + Returns the number of net buffers linked to the net buffer list. + + Optionally retuens the total byte count of all net buffers linked + to the net buffer list + + Runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + + NetBufferList The NBL to examine + +Return Value: + + The number of net buffers linked to the net buffer list. + +--*/ +{ + ULONG netBufferCount = 0; + PNET_BUFFER currentNb; + + if(TotalByteCount) + { + *TotalByteCount = 0; + } + + currentNb = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + + while(currentNb) + { + ++netBufferCount; + + if(TotalByteCount) + { + *TotalByteCount += NET_BUFFER_DATA_LENGTH(currentNb); + } + + // Move to next NB + currentNb = NET_BUFFER_NEXT_NB(currentNb); + } + + return netBufferCount; +} + +VOID +tapAdapterAcquireLock( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in BOOLEAN DispatchLevel + ) +{ + ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql())); + + if (DispatchLevel) + { + NdisDprAcquireSpinLock(&Adapter->AdapterLock); + } + else + { + NdisAcquireSpinLock(&Adapter->AdapterLock); + } +} + +VOID +tapAdapterReleaseLock( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in BOOLEAN DispatchLevel + ) +{ + ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql())); + + if (DispatchLevel) + { + NdisDprReleaseSpinLock(&Adapter->AdapterLock); + } + else + { + NdisReleaseSpinLock(&Adapter->AdapterLock); + } +} + + diff --git a/windows/TapDriver6/adapter.h b/windows/TapDriver6/adapter.h new file mode 100644 index 00000000..0ebaaea7 --- /dev/null +++ b/windows/TapDriver6/adapter.h @@ -0,0 +1,352 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_ADAPTER_CONTEXT_H_ +#define __TAP_ADAPTER_CONTEXT_H_ + +#include "tap.h" + +// Memory allocation tags. +#define TAP_ADAPTER_TAG ((ULONG)'ApaT') // "TapA +#define TAP_RX_NBL_TAG ((ULONG)'RpaT') // "TapR +#define TAP_RX_INJECT_BUFFER_TAG ((ULONG)'IpaT') // "TapI + +#define TAP_MAX_NDIS_NAME_LENGTH 64 // 38 character GUID string plus extra.. + +// TAP receive indication NBL flag definitions. +#define TAP_RX_NBL_FLAGS NBL_FLAGS_MINIPORT_RESERVED +#define TAP_RX_NBL_FLAGS_CLEAR_ALL(_NBL) ((_NBL)->Flags &= ~TAP_RX_NBL_FLAGS) +#define TAP_RX_NBL_FLAG_SET(_NBL, _F) ((_NBL)->Flags |= ((_F) & TAP_RX_NBL_FLAGS)) +#define TAP_RX_NBL_FLAG_CLEAR(_NBL, _F) ((_NBL)->Flags &= ~((_F) & TAP_RX_NBL_FLAGS)) +#define TAP_RX_NBL_FLAG_TEST(_NBL, _F) (((_NBL)->Flags & ((_F) & TAP_RX_NBL_FLAGS)) != 0) + +#define TAP_RX_NBL_FLAGS_IS_P2P 0x00001000 +#define TAP_RX_NBL_FLAGS_IS_INJECTED 0x00002000 + +// MSDN Ref: http://msdn.microsoft.com/en-us/library/windows/hardware/ff560490(v=vs.85).aspx +typedef +enum _TAP_MINIPORT_ADAPTER_STATE +{ + // The Halted state is the initial state of all adapters. When an + // adapter is in the Halted state, NDIS can call the driver's + // MiniportInitializeEx function to initialize the adapter. + MiniportHaltedState, + + // In the Shutdown state, a system shutdown and restart must occur + // before the system can use the adapter again. + MiniportShutdownState, + + // In the Initializing state, a miniport driver completes any + //operations that are required to initialize an adapter. + MiniportInitializingState, + + // Entering the Paused state... + MiniportPausingState, + + // In the Paused state, the adapter does not indicate received + // network data or accept send requests. + MiniportPausedState, + + // In the Running state, a miniport driver performs send and + // receive processing for an adapter. + MiniportRunning, + + // In the Restarting state, a miniport driver completes any + // operations that are required to restart send and receive + // operations for an adapter. + MiniportRestartingState +} TAP_MINIPORT_ADAPTER_STATE, *PTAP_MINIPORT_ADAPTER_STATE; + +// +// Each adapter managed by this driver has a TapAdapter struct. +// ------------------------------------------------------------ +// Since there is a one-to-one relationship between adapter instances +// and device instances this structure is the device extension as well. +// +typedef struct _TAP_ADAPTER_CONTEXT +{ + LIST_ENTRY AdapterListLink; + + volatile LONG RefCount; + + NDIS_HANDLE MiniportAdapterHandle; + + NDIS_SPIN_LOCK AdapterLock; // Lock for protection of state and outstanding sends and recvs + + // + // All fields that are protected by the AdapterLock are included + // in the Locked structure to remind us to take the Lock + // before accessing them :) + // + struct + { + TAP_MINIPORT_ADAPTER_STATE AdapterState; + } Locked; + + BOOLEAN ResetInProgress; + + // + // NetCfgInstanceId as UNICODE_STRING + // ---------------------------------- + // This a GUID string provided by NDIS that identifies the adapter instance. + // An example is: + // + // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} + // + // Other names are derived from NetCfgInstanceId. For example, MiniportName: + // + // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} + // + NDIS_STRING NetCfgInstanceId; + WCHAR NetCfgInstanceIdBuffer[TAP_MAX_NDIS_NAME_LENGTH]; + +# define MINIPORT_INSTANCE_ID(a) ((a)->NetCfgInstanceIdAnsi.Buffer) + ANSI_STRING NetCfgInstanceIdAnsi; // Used occasionally + + ULONG MtuSize; // 1500 byte (typical) + + // TRUE if adapter should always be "connected" even when device node + // is not open by a userspace process. + // + // FALSE if connection state is application controlled. + BOOLEAN MediaStateAlwaysConnected; + + // TRUE if device is "connected". + BOOLEAN LogicalMediaState; + + NDIS_DEVICE_POWER_STATE CurrentPowerState; + + BOOLEAN AllowNonAdmin; + + MACADDR PermanentAddress; // From registry, if available + MACADDR CurrentAddress; + + // Device registration parameters from NdisRegisterDeviceEx. + NDIS_STRING DeviceName; + WCHAR DeviceNameBuffer[TAP_MAX_NDIS_NAME_LENGTH]; + + NDIS_STRING LinkName; + WCHAR LinkNameBuffer[TAP_MAX_NDIS_NAME_LENGTH]; + + NDIS_HANDLE DeviceHandle; + PDEVICE_OBJECT DeviceObject; + BOOLEAN TapDeviceCreated; // WAS: m_TapIsRunning + + PFILE_OBJECT TapFileObject; // Exclusive access + BOOLEAN TapFileIsOpen; // WAS: m_TapOpens + LONG TapFileOpenCount; // WAS: m_NumTapOpens + + // Cancel-Safe read IRP queue. + TAP_IRP_CSQ PendingReadIrpQueue; + + // Queue containing TAP packets representing host send NBs. These are + // waiting to be read by user-mode application. + TAP_PACKET_QUEUE SendPacketQueue; + + // NBL pool for making TAP receive indications. + NDIS_HANDLE ReceiveNblPool; + + volatile LONG ReceiveNblInFlightCount; +#define TAP_WAIT_POLL_LOOP_TIMEOUT 3000 // 3 seconds + NDIS_EVENT ReceiveNblInFlightCountZeroEvent; + + /* + // Info for point-to-point mode + BOOLEAN m_tun; + IPADDR m_localIP; + IPADDR m_remoteNetwork; + IPADDR m_remoteNetmask; + ETH_HEADER m_TapToUser; + ETH_HEADER m_UserToTap; + ETH_HEADER m_UserToTap_IPv6; // same as UserToTap but proto=ipv6 + */ + + // Info for DHCP server masquerade + /* + BOOLEAN m_dhcp_enabled; + IPADDR m_dhcp_addr; + ULONG m_dhcp_netmask; + IPADDR m_dhcp_server_ip; + BOOLEAN m_dhcp_server_arp; + MACADDR m_dhcp_server_mac; + ULONG m_dhcp_lease_time; + UCHAR m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE]; + ULONG m_dhcp_user_supplied_options_buffer_len; + BOOLEAN m_dhcp_received_discover; + ULONG m_dhcp_bad_requests; + */ + + // Multicast list. Fixed size. + ULONG ulMCListSize; + UCHAR MCList[TAP_MAX_MCAST_LIST][MACADDR_SIZE]; + + ULONG PacketFilter; + ULONG ulLookahead; + + // + // Statistics + // ------------------------------------------------------------------------- + // + + // Packet counts + ULONG64 FramesRxDirected; + ULONG64 FramesRxMulticast; + ULONG64 FramesRxBroadcast; + ULONG64 FramesTxDirected; + ULONG64 FramesTxMulticast; + ULONG64 FramesTxBroadcast; + + // Byte counts + ULONG64 BytesRxDirected; + ULONG64 BytesRxMulticast; + ULONG64 BytesRxBroadcast; + ULONG64 BytesTxDirected; + ULONG64 BytesTxMulticast; + ULONG64 BytesTxBroadcast; + + // Count of transmit errors + ULONG TxAbortExcessCollisions; + ULONG TxLateCollisions; + ULONG TxDmaUnderrun; + ULONG TxLostCRS; + ULONG TxOKButDeferred; + ULONG OneRetry; + ULONG MoreThanOneRetry; + ULONG TotalRetries; + ULONG TransmitFailuresOther; + + // Count of receive errors + ULONG RxCrcErrors; + ULONG RxAlignmentErrors; + ULONG RxResourceErrors; + ULONG RxDmaOverrunErrors; + ULONG RxCdtFrames; + ULONG RxRuntErrors; + +#if PACKET_TRUNCATION_CHECK + LONG m_RxTrunc, m_TxTrunc; +#endif + + BOOLEAN m_InterfaceIsRunning; + LONG m_Rx, m_RxErr; + NDIS_MEDIUM m_Medium; + + // Help to tear down the adapter by keeping + // some state information on allocated + // resources. + BOOLEAN m_CalledAdapterFreeResources; + BOOLEAN m_RegisteredAdapterShutdownHandler; + +} TAP_ADAPTER_CONTEXT, *PTAP_ADAPTER_CONTEXT; + +FORCEINLINE +LONG +tapAdapterContextReference( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + LONG refCount = NdisInterlockedIncrement(&Adapter->RefCount); + + ASSERT(refCount>1); // Cannot dereference a zombie. + + return refCount; +} + +VOID +tapAdapterContextFree( + __in PTAP_ADAPTER_CONTEXT Adapter + ); + +FORCEINLINE +LONG +tapAdapterContextDereference( + IN PTAP_ADAPTER_CONTEXT Adapter + ) +{ + LONG refCount = NdisInterlockedDecrement(&Adapter->RefCount); + ASSERT(refCount >= 0); + if (!refCount) + { + tapAdapterContextFree(Adapter); + } + + return refCount; +} + +VOID +tapAdapterAcquireLock( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in BOOLEAN DispatchLevel + ); + +VOID +tapAdapterReleaseLock( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in BOOLEAN DispatchLevel + ); + +// Returns with added reference on adapter context. +PTAP_ADAPTER_CONTEXT +tapAdapterContextFromDeviceObject( + __in PDEVICE_OBJECT DeviceObject + ); + +BOOLEAN +tapAdapterReadAndWriteReady( + __in PTAP_ADAPTER_CONTEXT Adapter + ); + +NDIS_STATUS +tapAdapterSendAndReceiveReady( + __in PTAP_ADAPTER_CONTEXT Adapter + ); + +ULONG +tapGetNetBufferFrameType( + __in PNET_BUFFER NetBuffer + ); + +ULONG +tapGetNetBufferCountsFromNetBufferList( + __in PNET_BUFFER_LIST NetBufferList, + __inout_opt PULONG TotalByteCount // Of all linked NBs + ); + +// Prototypes for standard NDIS miniport entry points +MINIPORT_SET_OPTIONS AdapterSetOptions; +MINIPORT_INITIALIZE AdapterCreate; +MINIPORT_HALT AdapterHalt; +MINIPORT_UNLOAD TapDriverUnload; +MINIPORT_PAUSE AdapterPause; +MINIPORT_RESTART AdapterRestart; +MINIPORT_OID_REQUEST AdapterOidRequest; +MINIPORT_SEND_NET_BUFFER_LISTS AdapterSendNetBufferLists; +MINIPORT_RETURN_NET_BUFFER_LISTS AdapterReturnNetBufferLists; +MINIPORT_CANCEL_SEND AdapterCancelSend; +MINIPORT_CHECK_FOR_HANG AdapterCheckForHangEx; +MINIPORT_RESET AdapterReset; +MINIPORT_DEVICE_PNP_EVENT_NOTIFY AdapterDevicePnpEventNotify; +MINIPORT_SHUTDOWN AdapterShutdownEx; +MINIPORT_CANCEL_OID_REQUEST AdapterCancelOidRequest; + +#endif // __TAP_ADAPTER_CONTEXT_H_
\ No newline at end of file diff --git a/windows/TapDriver6/config.h b/windows/TapDriver6/config.h new file mode 100644 index 00000000..4d36c5a1 --- /dev/null +++ b/windows/TapDriver6/config.h @@ -0,0 +1,9 @@ +#define PRODUCT_NAME "ZeroTier One Virtual Port" +#define PRODUCT_VERSION "3.0.0" +#define PRODUCT_VERSION_RESOURCE 3,0,0,1 +#define PRODUCT_TAP_WIN_COMPONENT_ID "zttap300" +#define PRODUCT_TAP_WIN_MAJOR 3 +#define PRODUCT_TAP_WIN_MINOR 0 +#define PRODUCT_TAP_WIN_PROVIDER "ZeroTier Networks" +#define PRODUCT_TAP_WIN_DEVICE_DESCRIPTION PRODUCT_NAME +#define PRODUCT_TAP_WIN_RELDATE "04/25/2015" diff --git a/windows/TapDriver6/constants.h b/windows/TapDriver6/constants.h new file mode 100644 index 00000000..91a876f2 --- /dev/null +++ b/windows/TapDriver6/constants.h @@ -0,0 +1,196 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//==================================================================== +// Product and Version public settings +//==================================================================== + +#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION + + +// +// Update the driver version number every time you release a new driver +// The high word is the major version. The low word is the minor version. +// Also make sure that VER_FILEVERSION specified in the .RC file also +// matches with the driver version because NDISTESTER checks for that. +// +#ifndef TAP_DRIVER_MAJOR_VERSION + +#define TAP_DRIVER_MAJOR_VERSION 0x04 +#define TAP_DRIVER_MINOR_VERSION 0x02 + +#endif + +#define TAP_DRIVER_VENDOR_VERSION ((TAP_DRIVER_MAJOR_VERSION << 16) | TAP_DRIVER_MINOR_VERSION) + +// +// Define the NDIS miniport interface version that this driver targets. +// +#if defined(NDIS60_MINIPORT) +# define TAP_NDIS_MAJOR_VERSION 6 +# define TAP_NDIS_MINOR_VERSION 0 +#elif defined(NDIS61_MINIPORT) +# define TAP_NDIS_MAJOR_VERSION 6 +# define TAP_NDIS_MINOR_VERSION 1 +#elif defined(NDIS620_MINIPORT) +# define TAP_NDIS_MAJOR_VERSION 6 +# define TAP_NDIS_MINOR_VERSION 20 +#elif defined(NDIS630_MINIPORT) +# define TAP_NDIS_MAJOR_VERSION 6 +# define TAP_NDIS_MINOR_VERSION 30 +#else +#define TAP_NDIS_MAJOR_VERSION 5 +#define TAP_NDIS_MINOR_VERSION 0 +#endif + +//=========================================================== +// Driver constants +//=========================================================== + +#define ETHERNET_HEADER_SIZE (sizeof (ETH_HEADER)) +//#define ETHERNET_MTU 1500 +#define ETHERNET_MTU 2800 +#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE) +#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE) +#define VLAN_TAG_SIZE 4 + +//=========================================================== +// Medium properties +//=========================================================== + +#define TAP_FRAME_HEADER_SIZE ETHERNET_HEADER_SIZE +#define TAP_FRAME_MAX_DATA_SIZE ETHERNET_MTU +#define TAP_MAX_FRAME_SIZE (TAP_FRAME_HEADER_SIZE + TAP_FRAME_MAX_DATA_SIZE) +#define TAP_MIN_FRAME_SIZE 60 + +#define TAP_MEDIUM_TYPE NdisMedium802_3 + +//=========================================================== +// Physical adapter properties +//=========================================================== + +// The bus that connects the adapter to the PC. +// (Example: PCI adapters should use NdisInterfacePci). +#define TAP_INTERFACE_TYPE NdisInterfaceInternal + +#define TAP_VENDOR_DESC PRODUCT_TAP_WIN_DEVICE_DESCRIPTION + +// Highest byte is the NIC byte plus three vendor bytes. This is normally +// obtained from the NIC. +#define TAP_VENDOR_ID 0x00FFFFFF + +// If you have physical hardware on 802.3, use NdisPhysicalMedium802_3. +#define TAP_PHYSICAL_MEDIUM NdisPhysicalMediumUnspecified + +// Claim to be 100mbps duplex +#define MEGABITS_PER_SECOND 1000000ULL +#define TAP_XMIT_SPEED (100ULL*MEGABITS_PER_SECOND) +#define TAP_RECV_SPEED (100ULL*MEGABITS_PER_SECOND) + +// Max number of multicast addresses supported in hardware +#define TAP_MAX_MCAST_LIST 128 + +#define TAP_MAX_LOOKAHEAD TAP_FRAME_MAX_DATA_SIZE +#define TAP_BUFFER_SIZE TAP_MAX_FRAME_SIZE + +// Set this value to TRUE if there is a physical adapter. +#define TAP_HAS_PHYSICAL_CONNECTOR FALSE +#define TAP_ACCESS_TYPE NET_IF_ACCESS_BROADCAST +#define TAP_DIRECTION_TYPE NET_IF_DIRECTION_SENDRECEIVE +#define TAP_CONNECTION_TYPE NET_IF_CONNECTION_DEDICATED + +// This value must match the *IfType in the driver .inf file +#define TAP_IFTYPE IF_TYPE_ETHERNET_CSMACD + +// +// This is a virtual device, so it can tolerate surprise removal and +// suspend. Ensure the correct flags are set for your hardware. +// +#define TAP_ADAPTER_ATTRIBUTES_FLAGS (\ + NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK | NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM) + +#define TAP_SUPPORTED_FILTERS ( \ + NDIS_PACKET_TYPE_DIRECTED | \ + NDIS_PACKET_TYPE_MULTICAST | \ + NDIS_PACKET_TYPE_BROADCAST | \ + NDIS_PACKET_TYPE_ALL_LOCAL | \ + NDIS_PACKET_TYPE_PROMISCUOUS | \ + NDIS_PACKET_TYPE_ALL_MULTICAST) + +//#define TAP_MAX_MCAST_LIST 128 // Max length of multicast address list + +// +// Specify a bitmask that defines optional properties of the NIC. +// This miniport indicates receive with NdisMIndicateReceiveNetBufferLists +// function. Such a driver should set this NDIS_MAC_OPTION_TRANSFERS_NOT_PEND +// flag. +// +// NDIS_MAC_OPTION_NO_LOOPBACK tells NDIS that NIC has no internal +// loopback support so NDIS will manage loopbacks on behalf of +// this driver. +// +// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA tells the protocol that +// our receive buffer is not on a device-specific card. If +// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA is not set, multi-buffer +// indications are copied to a single flat buffer. +// + +#define TAP_MAC_OPTIONS (\ + NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ + NDIS_MAC_OPTION_NO_LOOPBACK) + +#define TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS 4 + + +// NDIS 6.x miniports must support all counters in OID_GEN_STATISTICS. +#define TAP_SUPPORTED_STATISTICS (\ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | \ + NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | \ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | \ + NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | \ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT) + + +#define MINIMUM_MTU 576 // USE TCP Minimum MTU +#define MAXIMUM_MTU 65536 // IP maximum MTU + +#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size +#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace +#define INJECT_QUEUE_SIZE 16 // DHCP/ARP -> tap injection queue + +#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions diff --git a/windows/TapDriver6/device.c b/windows/TapDriver6/device.c new file mode 100644 index 00000000..7367143b --- /dev/null +++ b/windows/TapDriver6/device.c @@ -0,0 +1,1209 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" +#include <wdmsec.h> // for SDDLs + +//====================================================================== +// TAP Win32 Device I/O Callbacks +//====================================================================== + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( PAGE, TapDeviceCreate) +#pragma alloc_text( PAGE, TapDeviceControl) +#pragma alloc_text( PAGE, TapDeviceCleanup) +#pragma alloc_text( PAGE, TapDeviceClose) +#endif // ALLOC_PRAGMA + +//=================================================================== +// Go back to default TAP mode from Point-To-Point mode. +// Also reset (i.e. disable) DHCP Masq mode. +//=================================================================== +VOID tapResetAdapterState( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + /* + // Point-To-Point + Adapter->m_tun = FALSE; + Adapter->m_localIP = 0; + Adapter->m_remoteNetwork = 0; + Adapter->m_remoteNetmask = 0; + NdisZeroMemory (&Adapter->m_TapToUser, sizeof (Adapter->m_TapToUser)); + NdisZeroMemory (&Adapter->m_UserToTap, sizeof (Adapter->m_UserToTap)); + NdisZeroMemory (&Adapter->m_UserToTap_IPv6, sizeof (Adapter->m_UserToTap_IPv6)); + */ + + // DHCP Masq + /* + Adapter->m_dhcp_enabled = FALSE; + Adapter->m_dhcp_server_arp = FALSE; + Adapter->m_dhcp_user_supplied_options_buffer_len = 0; + Adapter->m_dhcp_addr = 0; + Adapter->m_dhcp_netmask = 0; + Adapter->m_dhcp_server_ip = 0; + Adapter->m_dhcp_lease_time = 0; + Adapter->m_dhcp_received_discover = FALSE; + Adapter->m_dhcp_bad_requests = 0; + NdisZeroMemory (Adapter->m_dhcp_server_mac, MACADDR_SIZE); + */ +} + +// IRP_MJ_CREATE +NTSTATUS +TapDeviceCreate( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + This routine is called by the I/O system when the device is opened. + + No action is performed other than completing the request successfully. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ +{ + NDIS_STATUS status; + PIO_STACK_LOCATION irpSp;// Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + PFILE_OBJECT originalFileObject; + + PAGED_CODE(); + + DEBUGP (("[TAP] --> TapDeviceCreate\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Invalidate file context + // + irpSp->FileObject->FsContext = NULL; + irpSp->FileObject->FsContext2 = NULL; + + // + // Find adapter context for this device. + // ------------------------------------- + // Returns with added reference on adapter context. + // + adapter = tapAdapterContextFromDeviceObject(DeviceObject); + + // Insure that adapter exists. + ASSERT(adapter); + + if(adapter == NULL ) + { + DEBUGP (("[TAP] release [%d.%d] open request; adapter not found\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION + )); + + Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return STATUS_DEVICE_DOES_NOT_EXIST; + } + + DEBUGP(("[%s] [TAP] release [%d.%d] open request (TapFileIsOpen=%d)\n", + MINIPORT_INSTANCE_ID(adapter), + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + adapter->TapFileIsOpen + )); + + // Enforce exclusive access + originalFileObject = InterlockedCompareExchangePointer( + &adapter->TapFileObject, + irpSp->FileObject, + NULL + ); + + if(originalFileObject == NULL) + { + irpSp->FileObject->FsContext = adapter; // Quick reference + + status = STATUS_SUCCESS; + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + // Release the lock. + //tapAdapterReleaseLock(adapter,FALSE); + + if(status == STATUS_SUCCESS) + { + // Reset adapter state on successful open. + tapResetAdapterState(adapter); + + adapter->TapFileIsOpen = 1; // Legacy... + + // NOTE!!! Reference added by tapAdapterContextFromDeviceObject + // will be removed when file is closed. + } + else + { + DEBUGP (("[%s] TAP is presently unavailable (TapFileIsOpen=%d)\n", + MINIPORT_INSTANCE_ID(adapter), adapter->TapFileIsOpen + )); + + NOTE_ERROR(); + + // Remove reference added by tapAdapterContextFromDeviceObject. + tapAdapterContextDereference(adapter); + } + + // Complete the IRP. + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + DEBUGP (("[TAP] <-- TapDeviceCreate; status = %8.8X\n",status)); + + return status; +} + +//=================================================== +// Tell Windows whether the TAP device should be +// considered "connected" or "disconnected". +// +// Allows application control of media connect state. +//=================================================== +VOID +tapSetMediaConnectStatus( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in BOOLEAN LogicalMediaState + ) +{ + NDIS_STATUS_INDICATION statusIndication; + NDIS_LINK_STATE linkState; + + NdisZeroMemory(&statusIndication, sizeof(NDIS_STATUS_INDICATION)); + NdisZeroMemory(&linkState, sizeof(NDIS_LINK_STATE)); + + // + // Fill in object headers + // + statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION; + statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1; + statusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION); + + linkState.Header.Revision = NDIS_LINK_STATE_REVISION_1; + linkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + linkState.Header.Size = sizeof(NDIS_LINK_STATE); + + // + // Link state buffer + // + if(Adapter->LogicalMediaState == TRUE) + { + linkState.MediaConnectState = MediaConnectStateConnected; + } + + linkState.MediaDuplexState = MediaDuplexStateFull; + linkState.RcvLinkSpeed = TAP_RECV_SPEED; + linkState.XmitLinkSpeed = TAP_XMIT_SPEED; + + // + // Fill in the status buffer + // + statusIndication.StatusCode = NDIS_STATUS_LINK_STATE; + statusIndication.SourceHandle = Adapter->MiniportAdapterHandle; + statusIndication.DestinationHandle = NULL; + statusIndication.RequestId = 0; + + statusIndication.StatusBuffer = &linkState; + statusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE); + + // Fill in new media connect state. + if ( (Adapter->LogicalMediaState != LogicalMediaState) && !Adapter->MediaStateAlwaysConnected) + { + Adapter->LogicalMediaState = LogicalMediaState; + + if (LogicalMediaState == TRUE) + { + linkState.MediaConnectState = MediaConnectStateConnected; + + DEBUGP (("[TAP] Set MediaConnectState: Connected.\n")); + } + else + { + linkState.MediaConnectState = MediaConnectStateDisconnected; + + DEBUGP (("[TAP] Set MediaConnectState: Disconnected.\n")); + } + } + + // Make the status indication. + if(Adapter->Locked.AdapterState != MiniportHaltedState) + { + NdisMIndicateStatusEx(Adapter->MiniportAdapterHandle, &statusIndication); + } +} + +/* +//====================================================== +// If DHCP mode is used together with tun +// mode, consider the fact that the P2P remote subnet +// might enclose the DHCP masq server address. +//====================================================== +VOID +CheckIfDhcpAndTunMode ( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + if (Adapter->m_tun && Adapter->m_dhcp_enabled) + { + if ((Adapter->m_dhcp_server_ip & Adapter->m_remoteNetmask) == Adapter->m_remoteNetwork) + { + ETH_COPY_NETWORK_ADDRESS (Adapter->m_dhcp_server_mac, Adapter->m_TapToUser.dest); + Adapter->m_dhcp_server_arp = FALSE; + } + } +} +*/ + +// IRP_MJ_DEVICE_CONTROL callback. +NTSTATUS +TapDeviceControl( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine is called by the I/O system to perform a device I/O + control function. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + ULONG inBufLength; // Input buffer length + ULONG outBufLength; // Output buffer length + PCHAR inBuf, outBuf; // pointer to Input and output buffer + PMDL mdl = NULL; + PCHAR buffer = NULL; + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation( Irp ); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; + + ASSERT(adapter); + + inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; + outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; + + if (!inBufLength || !outBufLength) + { + ntStatus = STATUS_INVALID_PARAMETER; + goto End; + } + + // + // Determine which I/O control code was specified. + // + switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) + { + case TAP_WIN_IOCTL_GET_MAC: + { + if (outBufLength >= MACADDR_SIZE ) + { + ETH_COPY_NETWORK_ADDRESS( + Irp->AssociatedIrp.SystemBuffer, + adapter->CurrentAddress + ); + + Irp->IoStatus.Information = MACADDR_SIZE; + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } + break; + + case TAP_WIN_IOCTL_GET_VERSION: + { + const ULONG size = sizeof (ULONG) * 3; + + if (outBufLength >= size) + { + ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0] + = TAP_DRIVER_MAJOR_VERSION; + + ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[1] + = TAP_DRIVER_MINOR_VERSION; + + ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[2] +#if DBG + = 1; +#else + = 0; +#endif + Irp->IoStatus.Information = size; + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } + break; + + case TAP_WIN_IOCTL_GET_MTU: + { + const ULONG size = sizeof (ULONG) * 1; + + if (outBufLength >= size) + { + ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0] + = adapter->MtuSize; + + Irp->IoStatus.Information = size; + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } + break; + + // Allow ZeroTier One to get multicast memberships at the L2 level in a + // protocol-neutral manner. + case TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS: + { + if (outBufLength < TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE) { + /* output buffer too small */ + NOTE_ERROR (); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } else { + char *out = (char *)Irp->AssociatedIrp.SystemBuffer; + char *end = out + TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE; + unsigned long i,j; + for(i=0;i<adapter->ulMCListSize;++i) { + if (i >= TAP_MAX_MCAST_LIST) + break; + for(j=0;j<6;++j) + *(out++) = adapter->MCList[i][j]; + if (out >= end) + break; + } + while (out < end) + *(out++) = (char)0; + Irp->IoStatus.Information = TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE; + Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS; + } + break; + } + + +#if 0 + case TAP_WIN_IOCTL_CONFIG_TUN: + { + if(inBufLength >= sizeof(IPADDR)*3) + { + MACADDR dest; + + adapter->m_tun = FALSE; + + GenerateRelatedMAC (dest, adapter->CurrentAddress, 1); + + adapter->m_localIP = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0]; + adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1]; + adapter->m_remoteNetmask = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2]; + + // Sanity check on network/netmask + if ((adapter->m_remoteNetwork & adapter->m_remoteNetmask) != adapter->m_remoteNetwork) + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + break; + } + + ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress); + ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest); + ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest); + ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress); + + adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4); + adapter->m_UserToTap_IPv6 = adapter->m_UserToTap; + adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6); + + adapter->m_tun = TRUE; + + CheckIfDhcpAndTunMode (adapter); + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP (("[TAP] Set TUN mode.\n")); + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } + break; + + case TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: + { + if(inBufLength >= sizeof(IPADDR)*2) + { + MACADDR dest; + + adapter->m_tun = FALSE; + + GenerateRelatedMAC (dest, adapter->CurrentAddress, 1); + + adapter->m_localIP = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0]; + adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1]; + adapter->m_remoteNetmask = ~0; + + ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress); + ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest); + ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest); + ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress); + + adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4); + adapter->m_UserToTap_IPv6 = adapter->m_UserToTap; + adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6); + + adapter->m_tun = TRUE; + + CheckIfDhcpAndTunMode (adapter); + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP (("[TAP] Set P2P mode.\n")); + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } + break; +#endif + +#if 0 + case TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: + { + if(inBufLength >= sizeof(IPADDR)*4) + { + adapter->m_dhcp_enabled = FALSE; + adapter->m_dhcp_server_arp = FALSE; + adapter->m_dhcp_user_supplied_options_buffer_len = 0; + + // Adapter IP addr / netmask + adapter->m_dhcp_addr = + ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0]; + adapter->m_dhcp_netmask = + ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1]; + + // IP addr of DHCP masq server + adapter->m_dhcp_server_ip = + ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2]; + + // Lease time in seconds + adapter->m_dhcp_lease_time = + ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[3]; + + GenerateRelatedMAC( + adapter->m_dhcp_server_mac, + adapter->CurrentAddress, + 2 + ); + + adapter->m_dhcp_enabled = TRUE; + adapter->m_dhcp_server_arp = TRUE; + + CheckIfDhcpAndTunMode (adapter); + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP (("[TAP] Configured DHCP MASQ.\n")); + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } + break; + + case TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: + { + if (inBufLength <= DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE + && adapter->m_dhcp_enabled) + { + adapter->m_dhcp_user_supplied_options_buffer_len = 0; + + NdisMoveMemory( + adapter->m_dhcp_user_supplied_options_buffer, + Irp->AssociatedIrp.SystemBuffer, + inBufLength + ); + + adapter->m_dhcp_user_supplied_options_buffer_len = + inBufLength; + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP (("[TAP] Set DHCP OPT.\n")); + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } + break; +#endif + +#if 0 + case TAP_WIN_IOCTL_GET_INFO: + { + char state[16]; + + // Fetch adapter (miniport) state. + if (tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) + state[0] = 'A'; + else + state[0] = 'a'; + + if (tapAdapterReadAndWriteReady(adapter)) + state[1] = 'T'; + else + state[1] = 't'; + + state[2] = '0' + adapter->CurrentPowerState; + + if (adapter->MediaStateAlwaysConnected) + state[3] = 'C'; + else + state[3] = 'c'; + + state[4] = '\0'; + + // BUGBUG!!! What follows, and is not yet implemented, is a real mess. + // BUGBUG!!! Tied closely to the NDIS 5 implementation. Need to map + // as much as possible to the NDIS 6 implementation. + Irp->IoStatus.Status = ntStatus = RtlStringCchPrintfExA ( + ((LPTSTR) (Irp->AssociatedIrp.SystemBuffer)), + outBufLength, + NULL, + NULL, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS, +#if PACKET_TRUNCATION_CHECK + "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]", +#else + "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]", +#endif + state, + g_LastErrorFilename, + g_LastErrorLineNumber, + (int)adapter->TapFileOpenCount, + (int)(adapter->FramesTxDirected + adapter->FramesTxMulticast + adapter->FramesTxBroadcast), + (int)adapter->TransmitFailuresOther, +#if PACKET_TRUNCATION_CHECK + (int)adapter->m_TxTrunc, +#endif + (int)adapter->m_Rx, + (int)adapter->m_RxErr, +#if PACKET_TRUNCATION_CHECK + (int)adapter->m_RxTrunc, +#endif + (int)adapter->PendingReadIrpQueue.Count, + (int)adapter->PendingReadIrpQueue.MaxCount, + (int)IRP_QUEUE_SIZE, // Ignored in NDIS 6 driver... + + (int)adapter->SendPacketQueue.Count, + (int)adapter->SendPacketQueue.MaxCount, + (int)PACKET_QUEUE_SIZE, + + (int)0, // adapter->InjectPacketQueue.Count - Unused + (int)0, // adapter->InjectPacketQueue.MaxCount - Unused + (int)INJECT_QUEUE_SIZE + ); + + Irp->IoStatus.Information = outBufLength; + + // BUGBUG!!! Fail because this is not completely implemented. + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + } +#endif + +#if DBG + case TAP_WIN_IOCTL_GET_LOG_LINE: + { + if (GetDebugLine( (LPTSTR)Irp->AssociatedIrp.SystemBuffer,outBufLength)) + { + Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS; + } + else + { + Irp->IoStatus.Status = ntStatus = STATUS_UNSUCCESSFUL; + } + + Irp->IoStatus.Information = outBufLength; + + break; + } +#endif + + case TAP_WIN_IOCTL_SET_MEDIA_STATUS: + { + if(inBufLength >= sizeof(ULONG)) + { + ULONG parm = ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]; + tapSetMediaConnectStatus (adapter, (BOOLEAN) parm); + Irp->IoStatus.Information = 1; + } + else + { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } + break; + + default: + + // + // The specified I/O control code is unrecognized by this driver. + // + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + } + +End: + + // + // Finish the I/O operation by simply completing the packet and returning + // the same status as in the packet itself. + // + Irp->IoStatus.Status = ntStatus; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return ntStatus; +} + +// Flush the pending read IRP queue. +VOID +tapFlushIrpQueues( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + + DEBUGP (("[TAP] tapFlushIrpQueues: Flushing %d pending read IRPs\n", + Adapter->PendingReadIrpQueue.Count)); + + tapIrpCsqFlush(&Adapter->PendingReadIrpQueue); +} + +// IRP_MJ_CLEANUP +NTSTATUS +TapDeviceCleanup( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + Receipt of this request indicates that the last handle for a file + object that is associated with the target device object has been closed + (but, due to outstanding I/O requests, might not have been released). + + A driver that holds pending IRPs internally must implement a routine for + IRP_MJ_CLEANUP. When the routine is called, the driver should cancel all + the pending IRPs that belong to the file object identified by the IRP_MJ_CLEANUP + call. + + In other words, it should cancel all the IRPs that have the same file-object + pointer as the one supplied in the current I/O stack location of the IRP for the + IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should + not be canceled. Also, if an outstanding IRP is completed immediately, the + driver does not have to cancel it. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + to be cleaned up. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed. + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + + PAGED_CODE(); + + DEBUGP (("[TAP] --> TapDeviceCleanup\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; + + // Insure that adapter exists. + ASSERT(adapter); + + if(adapter == NULL ) + { + DEBUGP (("[TAP] release [%d.%d] cleanup request; adapter not found\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION + )); + } + + if(adapter != NULL ) + { + adapter->TapFileIsOpen = 0; // Legacy... + + // Disconnect from media. + tapSetMediaConnectStatus(adapter,FALSE); + + // Reset adapter state when cleaning up; + tapResetAdapterState(adapter); + + // BUGBUG!!! Use RemoveLock??? + + // + // Flush pending send TAP packet queue. + // + tapFlushSendPacketQueue(adapter); + + ASSERT(adapter->SendPacketQueue.Count == 0); + + // + // Flush the pending IRP queues + // + tapFlushIrpQueues(adapter); + + ASSERT(adapter->PendingReadIrpQueue.Count == 0); + } + + // Complete the IRP. + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + DEBUGP (("[TAP] <-- TapDeviceCleanup; status = %8.8X\n",status)); + + return status; +} + +// IRP_MJ_CLOSE +NTSTATUS +TapDeviceClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + Receipt of this request indicates that the last handle of the file + object that is associated with the target device object has been closed + and released. + + All outstanding I/O requests have been completed or canceled. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + to be closed. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed. + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + + PAGED_CODE(); + + DEBUGP (("[TAP] --> TapDeviceClose\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; + + // Insure that adapter exists. + ASSERT(adapter); + + if(adapter == NULL ) + { + DEBUGP (("[TAP] release [%d.%d] close request; adapter not found\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION + )); + } + + if(adapter != NULL ) + { + if(adapter->TapFileObject == NULL) + { + // Should never happen!!! + ASSERT(FALSE); + } + else + { + ASSERT(irpSp->FileObject->FsContext == adapter); + + ASSERT(adapter->TapFileObject == irpSp->FileObject); + } + + adapter->TapFileObject = NULL; + irpSp->FileObject = NULL; + + // Remove reference added by when handle was opened. + tapAdapterContextDereference(adapter); + } + + // Complete the IRP. + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + DEBUGP (("[TAP] <-- TapDeviceClose; status = %8.8X\n",status)); + + return status; +} + +NTSTATUS +tapConcatenateNdisStrings( + __inout PNDIS_STRING DestinationString, + __in_opt PNDIS_STRING SourceString1, + __in_opt PNDIS_STRING SourceString2, + __in_opt PNDIS_STRING SourceString3 + ) +{ + NTSTATUS status; + + ASSERT(SourceString1 && SourceString2 && SourceString3); + + status = RtlAppendUnicodeStringToString( + DestinationString, + SourceString1 + ); + + if(status == STATUS_SUCCESS) + { + status = RtlAppendUnicodeStringToString( + DestinationString, + SourceString2 + ); + + if(status == STATUS_SUCCESS) + { + status = RtlAppendUnicodeStringToString( + DestinationString, + SourceString3 + ); + } + } + + return status; +} + +NTSTATUS +tapMakeDeviceNames( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + NDIS_STATUS status; + NDIS_STRING deviceNamePrefix = NDIS_STRING_CONST("\\Device\\"); + NDIS_STRING tapNameSuffix = NDIS_STRING_CONST(".tap"); + + // Generate DeviceName from NetCfgInstanceId. + Adapter->DeviceName.Buffer = Adapter->DeviceNameBuffer; + Adapter->DeviceName.MaximumLength = sizeof(Adapter->DeviceNameBuffer); + + status = tapConcatenateNdisStrings( + &Adapter->DeviceName, + &deviceNamePrefix, + &Adapter->NetCfgInstanceId, + &tapNameSuffix + ); + + if(status == STATUS_SUCCESS) + { + NDIS_STRING linkNamePrefix = NDIS_STRING_CONST("\\DosDevices\\Global\\"); + + Adapter->LinkName.Buffer = Adapter->LinkNameBuffer; + Adapter->LinkName.MaximumLength = sizeof(Adapter->LinkNameBuffer); + + status = tapConcatenateNdisStrings( + &Adapter->LinkName, + &linkNamePrefix, + &Adapter->NetCfgInstanceId, + &tapNameSuffix + ); + } + + return status; +} + +NDIS_STATUS +CreateTapDevice( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + NDIS_STATUS status; + NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttribute; + PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; + + DEBUGP (("[TAP] version [%d.%d] creating tap device: %wZ\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + &Adapter->NetCfgInstanceId)); + + // Generate DeviceName and LinkName from NetCfgInstanceId. + status = tapMakeDeviceNames(Adapter); + + if (NT_SUCCESS(status)) + { + DEBUGP (("[TAP] DeviceName: %wZ\n",&Adapter->DeviceName)); + DEBUGP (("[TAP] LinkName: %wZ\n",&Adapter->LinkName)); + + // Initialize dispatch table. + NdisZeroMemory(dispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH)); + + dispatchTable[IRP_MJ_CREATE] = TapDeviceCreate; + dispatchTable[IRP_MJ_CLEANUP] = TapDeviceCleanup; + dispatchTable[IRP_MJ_CLOSE] = TapDeviceClose; + dispatchTable[IRP_MJ_READ] = TapDeviceRead; + dispatchTable[IRP_MJ_WRITE] = TapDeviceWrite; + dispatchTable[IRP_MJ_DEVICE_CONTROL] = TapDeviceControl; + + // + // Create a device object and register dispatch handlers + // + NdisZeroMemory(&deviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES)); + + deviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES; + deviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1; + deviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES); + + deviceAttribute.DeviceName = &Adapter->DeviceName; + deviceAttribute.SymbolicName = &Adapter->LinkName; + deviceAttribute.MajorFunctions = &dispatchTable[0]; + //deviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION); + +#if ENABLE_NONADMIN + if(Adapter->AllowNonAdmin) + { + // + // SDDL_DEVOBJ_SYS_ALL_WORLD_RWX_RES_RWX allows the kernel and system complete + // control over the device. By default the admin can access the entire device, + // but cannot change the ACL (the admin must take control of the device first) + // + // Everyone else, including "restricted" or "untrusted" code can read or write + // to the device. Traversal beneath the device is also granted (removing it + // would only effect storage devices, except if the "bypass-traversal" + // privilege was revoked). + // + deviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX; + } +#endif + + status = NdisRegisterDeviceEx( + Adapter->MiniportAdapterHandle, + &deviceAttribute, + &Adapter->DeviceObject, + &Adapter->DeviceHandle + ); + } + + ASSERT(NT_SUCCESS(status)); + + if (NT_SUCCESS(status)) + { + // Set TAP device flags. + (Adapter->DeviceObject)->Flags &= ~DO_BUFFERED_IO; + (Adapter->DeviceObject)->Flags |= DO_DIRECT_IO;; + + //======================== + // Finalize initialization + //======================== + + Adapter->TapDeviceCreated = TRUE; + + DEBUGP (("[%wZ] successfully created TAP device [%wZ]\n", + &Adapter->NetCfgInstanceId, + &Adapter->DeviceName + )); + } + + DEBUGP (("[TAP] <-- CreateTapDevice; status = %8.8X\n",status)); + + return status; +} + +// +// DestroyTapDevice is called from AdapterHalt and NDIS miniport +// is in Halted state. Prior to entering the Halted state the +// miniport would have passed through the Pausing and Paused +// states. These miniport states have responsibility for waiting +// until NDIS network operations have completed. +// +VOID +DestroyTapDevice( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + DEBUGP (("[TAP] --> DestroyTapDevice; Adapter: %wZ\n", + &Adapter->NetCfgInstanceId)); + + // + // Let clients know we are shutting down + // + Adapter->TapDeviceCreated = FALSE; + + // + // Flush pending send TAP packet queue. + // + tapFlushSendPacketQueue(Adapter); + + ASSERT(Adapter->SendPacketQueue.Count == 0); + + // + // Flush IRP queues. Wait for pending I/O. Etc. + // -------------------------------------------- + // Exhaust IRP and packet queues. Any pending IRPs will + // be cancelled, causing user-space to get this error + // on overlapped reads: + // + // ERROR_OPERATION_ABORTED, code=995 + // + // "The I/O operation has been aborted because of either a + // thread exit or an application request." + // + // It's important that user-space close the device handle + // when this code is returned, so that when we finally + // do a NdisMDeregisterDeviceEx, the device reference count + // is 0. Otherwise the driver will not unload even if the + // the last adapter has been halted. + // + // The act of flushing the queues at this point should result in the user-mode + // application closing the adapter's device handle. Closing the handle will + // result in the TapDeviceCleanup call being made, followed by the a call to + // the TapDeviceClose callback. + // + tapFlushIrpQueues(Adapter); + + ASSERT(Adapter->PendingReadIrpQueue.Count == 0); + + // + // Deregister the Win32 device. + // ---------------------------- + // When a driver calls NdisDeregisterDeviceEx, the I/O manager deletes the + // target device object if there are no outstanding references to it. However, + // if any outstanding references remain, the I/O manager marks the device + // object as "delete pending" and deletes the device object when the references + // are finally released. + // + if(Adapter->DeviceHandle) + { + DEBUGP (("[TAP] Calling NdisDeregisterDeviceEx\n")); + NdisDeregisterDeviceEx(Adapter->DeviceHandle); + } + + Adapter->DeviceHandle = NULL; + + DEBUGP (("[TAP] <-- DestroyTapDevice\n")); +} + diff --git a/windows/TapDriver6/device.h b/windows/TapDriver6/device.h new file mode 100644 index 00000000..93dae0d9 --- /dev/null +++ b/windows/TapDriver6/device.h @@ -0,0 +1,50 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __TAP_DEVICE_H_ +#define __TAP_DEVICE_H_ + +//====================================================================== +// TAP Prototypes for standard Win32 device I/O entry points +//====================================================================== + +__drv_dispatchType(IRP_MJ_CREATE) +DRIVER_DISPATCH TapDeviceCreate; + +__drv_dispatchType(IRP_MJ_READ) +DRIVER_DISPATCH TapDeviceRead; + +__drv_dispatchType(IRP_MJ_WRITE) +DRIVER_DISPATCH TapDeviceWrite; + +__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH TapDeviceControl; + +__drv_dispatchType(IRP_MJ_CLEANUP) +DRIVER_DISPATCH TapDeviceCleanup; + +__drv_dispatchType(IRP_MJ_CLOSE) +DRIVER_DISPATCH TapDeviceClose; + +#endif // __TAP_DEVICE_H_
\ No newline at end of file diff --git a/windows/TapDriver6/endian.h b/windows/TapDriver6/endian.h new file mode 100644 index 00000000..b7d34499 --- /dev/null +++ b/windows/TapDriver6/endian.h @@ -0,0 +1,35 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TAP_LITTLE_ENDIAN +#define ntohs(x) RtlUshortByteSwap(x) +#define htons(x) RtlUshortByteSwap(x) +#define ntohl(x) RtlUlongByteSwap(x) +#define htonl(x) RtlUlongByteSwap(x) +#else +#define ntohs(x) ((USHORT)(x)) +#define htons(x) ((USHORT)(x)) +#define ntohl(x) ((ULONG)(x)) +#define htonl(x) ((ULONG)(x)) +#endif diff --git a/windows/TapDriver6/error.c b/windows/TapDriver6/error.c new file mode 100644 index 00000000..1fad1d3a --- /dev/null +++ b/windows/TapDriver6/error.c @@ -0,0 +1,398 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tap.h" + +//----------------- +// DEBUGGING OUTPUT +//----------------- + +const char *g_LastErrorFilename; +int g_LastErrorLineNumber; + +#if DBG + +DebugOutput g_Debug; + +BOOLEAN +NewlineExists (const char *str, int len) +{ + while (len-- > 0) + { + const char c = *str++; + if (c == '\n') + return TRUE; + else if (c == '\0') + break; + } + return FALSE; +} + +VOID +MyDebugInit (unsigned int bufsiz) +{ + NdisZeroMemory (&g_Debug, sizeof (g_Debug)); + g_Debug.text = (char *) MemAlloc (bufsiz, FALSE); + + if (g_Debug.text) + { + g_Debug.capacity = bufsiz; + } +} + +VOID +MyDebugFree () +{ + if (g_Debug.text) + { + MemFree (g_Debug.text, g_Debug.capacity); + } + + NdisZeroMemory (&g_Debug, sizeof (g_Debug)); +} + +VOID +MyDebugPrint (const unsigned char* format, ...) +{ + if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT) + { + BOOLEAN owned; + ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); + if (owned) + { + const int remaining = (int)g_Debug.capacity - (int)g_Debug.out; + + if (remaining > 0) + { + va_list args; + NTSTATUS status; + char *end; + +#ifdef DBG_PRINT + va_start (args, format); + vDbgPrintEx (DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args); + va_end (args); +#endif + va_start (args, format); + status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out, + remaining, + &end, + NULL, + STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS, + format, + args); + va_end (args); + va_start (args, format); + vDbgPrintEx(DPFLTR_IHVDRIVER_ID , 1, format, args); + va_end (args); + if (status == STATUS_SUCCESS) + g_Debug.out = (unsigned int) (end - g_Debug.text); + else + g_Debug.error = TRUE; + } + else + g_Debug.error = TRUE; + + RELEASE_MUTEX (&g_Debug.lock); + } + else + g_Debug.error = TRUE; + } +} + +BOOLEAN +GetDebugLine ( + __in char *buf, + __in const int len + ) +{ + static const char *truncated = "[OUTPUT TRUNCATED]\n"; + BOOLEAN ret = FALSE; + + NdisZeroMemory (buf, len); + + if (g_Debug.text && g_Debug.capacity > 0) + { + BOOLEAN owned; + ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); + if (owned) + { + int i = 0; + + if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in)) + { + while (i < (len - 1) && g_Debug.in < g_Debug.out) + { + const char c = g_Debug.text[g_Debug.in++]; + if (c == '\n') + break; + buf[i++] = c; + } + if (i < len) + buf[i] = '\0'; + } + + if (!i) + { + if (g_Debug.in == g_Debug.out) + { + g_Debug.in = g_Debug.out = 0; + if (g_Debug.error) + { + const unsigned int tlen = strlen (truncated); + if (tlen < g_Debug.capacity) + { + NdisMoveMemory (g_Debug.text, truncated, tlen+1); + g_Debug.out = tlen; + } + g_Debug.error = FALSE; + } + } + } + else + ret = TRUE; + + RELEASE_MUTEX (&g_Debug.lock); + } + } + return ret; +} + +VOID +PrMac (const MACADDR mac) +{ + DEBUGP (("%x:%x:%x:%x:%x:%x", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5])); +} + +VOID +PrIP (IPADDR ip_addr) +{ + const unsigned char *ip = (const unsigned char *) &ip_addr; + + DEBUGP (("%d.%d.%d.%d", + ip[0], ip[1], ip[2], ip[3])); +} + +const char * +PrIPProto (int proto) +{ + switch (proto) + { + case IPPROTO_UDP: + return "UDP"; + + case IPPROTO_TCP: + return "TCP"; + + case IPPROTO_ICMP: + return "ICMP"; + + case IPPROTO_IGMP: + return "IGMP"; + + default: + return "???"; + } +} + +VOID +DumpARP (const char *prefix, const ARP_PACKET *arp) +{ + DEBUGP (("%s ARP src=", prefix)); + PrMac (arp->m_MAC_Source); + DEBUGP ((" dest=")); + PrMac (arp->m_MAC_Destination); + DEBUGP ((" OP=0x%04x", + (int)ntohs(arp->m_ARP_Operation))); + DEBUGP ((" M=0x%04x(%d)", + (int)ntohs(arp->m_MAC_AddressType), + (int)arp->m_MAC_AddressSize)); + DEBUGP ((" P=0x%04x(%d)", + (int)ntohs(arp->m_PROTO_AddressType), + (int)arp->m_PROTO_AddressSize)); + + DEBUGP ((" MacSrc=")); + PrMac (arp->m_ARP_MAC_Source); + DEBUGP ((" MacDest=")); + PrMac (arp->m_ARP_MAC_Destination); + + DEBUGP ((" IPSrc=")); + PrIP (arp->m_ARP_IP_Source); + DEBUGP ((" IPDest=")); + PrIP (arp->m_ARP_IP_Destination); + + DEBUGP (("\n")); +} + +struct ethpayload +{ + ETH_HEADER eth; + UCHAR payload[DEFAULT_PACKET_LOOKAHEAD]; +}; + +#ifdef ALLOW_PACKET_DUMP + +VOID +DumpPacket2( + __in const char *prefix, + __in const ETH_HEADER *eth, + __in const unsigned char *data, + __in unsigned int len + ) +{ + struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE); + if (ep) + { + if (len > DEFAULT_PACKET_LOOKAHEAD) + len = DEFAULT_PACKET_LOOKAHEAD; + ep->eth = *eth; + NdisMoveMemory (ep->payload, data, len); + DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len); + MemFree (ep, sizeof (struct ethpayload)); + } +} + +VOID +DumpPacket( + __in const char *prefix, + __in const unsigned char *data, + __in unsigned int len + ) +{ + const ETH_HEADER *eth = (const ETH_HEADER *) data; + const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER)); + + if (len < sizeof (ETH_HEADER)) + { + DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len)); + return; + } + + // ARP Packet? + if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP)) + { + DumpARP (prefix, (const ARP_PACKET *) data); + return; + } + + // IPv4 packet? + if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER)) + && eth->proto == htons (ETH_P_IP) + && IPH_GET_VER (ip->version_len) == 4) + { + const int hlen = IPH_GET_LEN (ip->version_len); + const int blen = len - sizeof (ETH_HEADER); + BOOLEAN did = FALSE; + + DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len)); + + if (!(ntohs (ip->tot_len) == blen && hlen <= blen)) + { + DEBUGP ((" XXX")); + return; + } + + // TCP packet? + if (ip->protocol == IPPROTO_TCP + && blen - hlen >= (sizeof (TCPHDR))) + { + const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen); + DEBUGP ((" ")); + PrIP (ip->saddr); + DEBUGP ((":%d", ntohs (tcp->source))); + DEBUGP ((" -> ")); + PrIP (ip->daddr); + DEBUGP ((":%d", ntohs (tcp->dest))); + did = TRUE; + } + + // UDP packet? + else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0 + && ip->protocol == IPPROTO_UDP + && blen - hlen >= (sizeof (UDPHDR))) + { + const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen); + + // DHCP packet? + if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT)) + && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP))) + { + const DHCP *dhcp = (DHCP *) (data + + hlen + + sizeof (ETH_HEADER) + + sizeof (UDPHDR)); + + int optlen = len + - sizeof (ETH_HEADER) + - hlen + - sizeof (UDPHDR) + - sizeof (DHCP); + + if (optlen < 0) + optlen = 0; + + DumpDHCP (eth, ip, udp, dhcp, optlen); + did = TRUE; + } + + if (!did) + { + DEBUGP ((" ")); + PrIP (ip->saddr); + DEBUGP ((":%d", ntohs (udp->source))); + DEBUGP ((" -> ")); + PrIP (ip->daddr); + DEBUGP ((":%d", ntohs (udp->dest))); + did = TRUE; + } + } + + if (!did) + { + DEBUGP ((" ipproto=%d ", ip->protocol)); + PrIP (ip->saddr); + DEBUGP ((" -> ")); + PrIP (ip->daddr); + } + + DEBUGP (("\n")); + return; + } + + { + DEBUGP (("%s ??? src=", prefix)); + PrMac (eth->src); + DEBUGP ((" dest=")); + PrMac (eth->dest); + DEBUGP ((" proto=0x%04x len=%d\n", + (int) ntohs(eth->proto), + len)); + } +} + +#endif // ALLOW_PACKET_DUMP + +#endif diff --git a/windows/TapDriver6/error.h b/windows/TapDriver6/error.h new file mode 100644 index 00000000..2ba39cc1 --- /dev/null +++ b/windows/TapDriver6/error.h @@ -0,0 +1,114 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//----------------- +// DEBUGGING OUTPUT +//----------------- + +extern const char *g_LastErrorFilename; +extern int g_LastErrorLineNumber; + +// Debug info output +#define ALSO_DBGPRINT 1 +#define DEBUGP_AT_DISPATCH 1 + +// Uncomment line below to allow packet dumps +//#define ALLOW_PACKET_DUMP 1 + +#define NOTE_ERROR() \ +{ \ + g_LastErrorFilename = __FILE__; \ + g_LastErrorLineNumber = __LINE__; \ +} + +#if DBG + +typedef struct +{ + unsigned int in; + unsigned int out; + unsigned int capacity; + char *text; + BOOLEAN error; + MUTEX lock; +} DebugOutput; + +VOID MyDebugPrint (const unsigned char* format, ...); + +VOID PrMac (const MACADDR mac); + +VOID PrIP (IPADDR ip_addr); + +#ifdef ALLOW_PACKET_DUMP + +VOID +DumpPacket( + __in const char *prefix, + __in const unsigned char *data, + __in unsigned int len + ); + +DumpPacket2( + __in const char *prefix, + __in const ETH_HEADER *eth, + __in const unsigned char *data, + __in unsigned int len + ); + +#else +#define DUMP_PACKET(prefix, data, len) +#define DUMP_PACKET2(prefix, eth, data, len) +#endif + +#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL) + +#if ALSO_DBGPRINT +#define DEBUGP(fmt) { MyDebugPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; } +#else +#define DEBUGP(fmt) { MyDebugPrint fmt; } +#endif + +#ifdef ALLOW_PACKET_DUMP + +#define DUMP_PACKET(prefix, data, len) \ + DumpPacket (prefix, data, len) + +#define DUMP_PACKET2(prefix, eth, data, len) \ + DumpPacket2 (prefix, eth, data, len) + +#endif + +BOOLEAN +GetDebugLine ( + __in char *buf, + __in const int len + ); + +#else + +#define DEBUGP(fmt) +#define DUMP_PACKET(prefix, data, len) +#define DUMP_PACKET2(prefix, eth, data, len) + +#endif diff --git a/windows/TapDriver6/hexdump.h b/windows/TapDriver6/hexdump.h new file mode 100644 index 00000000..d6275c18 --- /dev/null +++ b/windows/TapDriver6/hexdump.h @@ -0,0 +1,63 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HEXDUMP_DEFINED +#define HEXDUMP_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Debug Routines +//===================================================================================== + +#ifndef NDIS_MINIPORT_DRIVER +# include <stdio.h> +# include <ctype.h> +# include <windows.h> +# include <winnt.h> +# include <memory.h> + +# ifndef DEBUGP +# define DEBUGP(fmt) { DbgMessage fmt; } +# endif + + extern VOID (*DbgMessage)(char *p_Format, ...); + + VOID DisplayDebugString (char *p_Format, ...); +#endif + +//=================================================================================== +// Reporting / Debugging +//=================================================================================== +#define IfPrint(c) (c >= 32 && c < 127 ? c : '.') + +VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/windows/TapDriver6/lock.h b/windows/TapDriver6/lock.h new file mode 100644 index 00000000..c80b164c --- /dev/null +++ b/windows/TapDriver6/lock.h @@ -0,0 +1,75 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +typedef struct +{ + volatile long count; +} MUTEX; + +#define MUTEX_SLEEP_TIME 10000 // microseconds + +#define INIT_MUTEX(m) { (m)->count = 0; } + +#define ACQUIRE_MUTEX_BLOCKING(m) \ +{ \ + while (NdisInterlockedIncrement (&((m)->count)) != 1) \ + { \ + NdisInterlockedDecrement(&((m)->count)); \ + NdisMSleep(MUTEX_SLEEP_TIME); \ + } \ +} + +#define RELEASE_MUTEX(m) \ +{ \ + NdisInterlockedDecrement(&((m)->count)); \ +} + +#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \ +{ \ + if (NdisInterlockedIncrement (&((m)->count)) != 1) \ + { \ + NdisInterlockedDecrement(&((m)->count)); \ + result = FALSE; \ + } \ + else \ + { \ + result = TRUE; \ + } \ +} + +#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \ +{ \ + result = TRUE; \ + while (NdisInterlockedIncrement (&((m)->count)) != 1) \ + { \ + NdisInterlockedDecrement(&((m)->count)); \ + if (KeGetCurrentIrql () < DISPATCH_LEVEL) \ + NdisMSleep(MUTEX_SLEEP_TIME); \ + else \ + { \ + result = FALSE; \ + break; \ + } \ + } \ +} diff --git a/windows/TapDriver6/macinfo.c b/windows/TapDriver6/macinfo.c new file mode 100644 index 00000000..dfd0a075 --- /dev/null +++ b/windows/TapDriver6/macinfo.c @@ -0,0 +1,164 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "tap.h" + +int +HexStringToDecimalInt (const int p_Character) +{ + int l_Value = 0; + + if (p_Character >= 'A' && p_Character <= 'F') + l_Value = (p_Character - 'A') + 10; + else if (p_Character >= 'a' && p_Character <= 'f') + l_Value = (p_Character - 'a') + 10; + else if (p_Character >= '0' && p_Character <= '9') + l_Value = p_Character - '0'; + + return l_Value; +} + +BOOLEAN +ParseMAC (MACADDR dest, const char *src) +{ + int c; + int mac_index = 0; + BOOLEAN high_digit = FALSE; + int delim_action = 1; + + ASSERT (src); + ASSERT (dest); + + CLEAR_MAC (dest); + + while (c = *src++) + { + if (IsMacDelimiter (c)) + { + mac_index += delim_action; + high_digit = FALSE; + delim_action = 1; + } + else if (IsHexDigit (c)) + { + const int digit = HexStringToDecimalInt (c); + if (mac_index < sizeof (MACADDR)) + { + if (!high_digit) + { + dest[mac_index] = (char)(digit); + high_digit = TRUE; + delim_action = 1; + } + else + { + dest[mac_index] = (char)(dest[mac_index] * 16 + digit); + ++mac_index; + high_digit = FALSE; + delim_action = 0; + } + } + else + return FALSE; + } + else + return FALSE; + } + + return (mac_index + delim_action) >= sizeof (MACADDR); +} + +/* + * Generate a MAC using the GUID in the adapter name. + * + * The mac is constructed as 00:FF:xx:xx:xx:xx where + * the Xs are taken from the first 32 bits of the GUID in the + * adapter name. This is similar to the Linux 2.4 tap MAC + * generator, except linux uses 32 random bits for the Xs. + * + * In general, this solution is reasonable for most + * applications except for very large bridged TAP networks, + * where the probability of address collisions becomes more + * than infintesimal. + * + * Using the well-known "birthday paradox", on a 1000 node + * network the probability of collision would be + * 0.000116292153. On a 10,000 node network, the probability + * of collision would be 0.01157288998621678766. + */ + +VOID +GenerateRandomMac( + __in MACADDR mac, + __in const unsigned char *adapter_name + ) +{ + unsigned const char *cp = adapter_name; + unsigned char c; + unsigned int i = 2; + unsigned int byte = 0; + int brace = 0; + int state = 0; + + CLEAR_MAC (mac); + + mac[0] = 0x00; + mac[1] = 0xFF; + + while (c = *cp++) + { + if (i >= sizeof (MACADDR)) + break; + if (c == '{') + brace = 1; + if (IsHexDigit (c) && brace) + { + const unsigned int digit = HexStringToDecimalInt (c); + if (state) + { + byte <<= 4; + byte |= digit; + mac[i++] = (unsigned char) byte; + state = 0; + } + else + { + byte = digit; + state = 1; + } + } + } +} + +VOID +GenerateRelatedMAC( + __in MACADDR dest, + __in const MACADDR src, + __in const int delta + ) +{ + ETH_COPY_NETWORK_ADDRESS (dest, src); + dest[2] += (UCHAR) delta; +} diff --git a/windows/TapDriver6/macinfo.h b/windows/TapDriver6/macinfo.h new file mode 100644 index 00000000..dd88b6f8 --- /dev/null +++ b/windows/TapDriver6/macinfo.h @@ -0,0 +1,53 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MacInfoDefined +#define MacInfoDefined + +//=================================================================================== +// Macros +//=================================================================================== +#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.') +#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) + +#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR)) +#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0) + +BOOLEAN +ParseMAC (MACADDR dest, const char *src); + +VOID +GenerateRandomMac( + __in MACADDR mac, + __in const unsigned char *adapter_name + ); + +VOID +GenerateRelatedMAC( + __in MACADDR dest, + __in const MACADDR src, + __in const int delta + ); + +#endif diff --git a/windows/TapDriver6/mem.c b/windows/TapDriver6/mem.c new file mode 100644 index 00000000..ae2e3d40 --- /dev/null +++ b/windows/TapDriver6/mem.c @@ -0,0 +1,401 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//------------------ +// Memory Management +//------------------ + +#include "tap.h" + +PVOID +MemAlloc( + __in ULONG p_Size, + __in BOOLEAN zero + ) +{ + PVOID l_Return = NULL; + + if (p_Size) + { + __try + { + if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT') + == NDIS_STATUS_SUCCESS) + { + if (zero) + { + NdisZeroMemory (l_Return, p_Size); + } + } + else + { + l_Return = NULL; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + l_Return = NULL; + } + } + + return l_Return; +} + +VOID +MemFree( + __in PVOID p_Addr, + __in ULONG p_Size + ) +{ + if (p_Addr && p_Size) + { + __try + { +#if DBG + NdisZeroMemory (p_Addr, p_Size); +#endif + NdisFreeMemory (p_Addr, p_Size, 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + } +} + +//====================================================================== +// TAP Packet Queue Support +//====================================================================== + +VOID +tapPacketQueueInsertTail( + __in PTAP_PACKET_QUEUE TapPacketQueue, + __in PTAP_PACKET TapPacket + ) +{ + KIRQL irql; + + KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql); + + InsertTailList(&TapPacketQueue->Queue,&TapPacket->QueueLink); + + // BUGBUG!!! Enforce PACKET_QUEUE_SIZE queue count limit??? + // For NDIS 6 there is no per-packet status, so this will need to + // be handled on per-NBL basis in AdapterSendNetBufferLists... + + // Update counts + ++TapPacketQueue->Count; + + if(TapPacketQueue->Count > TapPacketQueue->MaxCount) + { + TapPacketQueue->MaxCount = TapPacketQueue->Count; + + DEBUGP (("[TAP] tapPacketQueueInsertTail: New MAX queued packet count = %d\n", + TapPacketQueue->MaxCount)); + } + + KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql); +} + +// Call with QueueLock held +PTAP_PACKET +tapPacketRemoveHeadLocked( + __in PTAP_PACKET_QUEUE TapPacketQueue + ) +{ + PTAP_PACKET tapPacket = NULL; + PLIST_ENTRY listEntry; + + listEntry = RemoveHeadList(&TapPacketQueue->Queue); + + if(listEntry != &TapPacketQueue->Queue) + { + tapPacket = CONTAINING_RECORD(listEntry, TAP_PACKET, QueueLink); + + // Update counts + --TapPacketQueue->Count; + } + + return tapPacket; +} + +PTAP_PACKET +tapPacketRemoveHead( + __in PTAP_PACKET_QUEUE TapPacketQueue + ) +{ + PTAP_PACKET tapPacket = NULL; + KIRQL irql; + + KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql); + + tapPacket = tapPacketRemoveHeadLocked(TapPacketQueue); + + KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql); + + return tapPacket; +} + +VOID +tapPacketQueueInitialize( + __in PTAP_PACKET_QUEUE TapPacketQueue + ) +{ + KeInitializeSpinLock(&TapPacketQueue->QueueLock); + + NdisInitializeListHead(&TapPacketQueue->Queue); +} + +//====================================================================== +// TAP Cancel-Safe Queue Support +//====================================================================== + +VOID +tapIrpCsqInsert ( + __in struct _IO_CSQ *Csq, + __in PIRP Irp + ) +{ + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ )Csq; + + InsertTailList( + &tapIrpCsq->Queue, + &Irp->Tail.Overlay.ListEntry + ); + + // Update counts + ++tapIrpCsq->Count; + + if(tapIrpCsq->Count > tapIrpCsq->MaxCount) + { + tapIrpCsq->MaxCount = tapIrpCsq->Count; + + DEBUGP (("[TAP] tapIrpCsqInsert: New MAX queued IRP count = %d\n", + tapIrpCsq->MaxCount)); + } +} + +VOID +tapIrpCsqRemoveIrp( + __in PIO_CSQ Csq, + __in PIRP Irp + ) +{ + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ )Csq; + + // Update counts + --tapIrpCsq->Count; + + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + + +PIRP +tapIrpCsqPeekNextIrp( + __in PIO_CSQ Csq, + __in PIRP Irp, + __in PVOID PeekContext + ) +{ + PTAP_IRP_CSQ tapIrpCsq; + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + PIO_STACK_LOCATION irpStack; + + tapIrpCsq = (PTAP_IRP_CSQ )Csq; + + listHead = &tapIrpCsq->Queue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if (Irp == NULL) + { + nextEntry = listHead->Flink; + } + else + { + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + } + + while(nextEntry != listHead) + { + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + irpStack = IoGetCurrentIrpStackLocation(nextIrp); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + if (PeekContext) + { + if (irpStack->FileObject == (PFILE_OBJECT) PeekContext) + { + break; + } + } + else + { + break; + } + + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + return nextIrp; +} + +// +// tapIrpCsqAcquireQueueLock modifies the execution level of the current processor. +// +// KeAcquireSpinLock raises the execution level to Dispatch Level and stores +// the current execution level in the Irql parameter to be restored at a later +// time. KeAcqurieSpinLock also requires us to be running at no higher than +// Dispatch level when it is called. +// +// The annotations reflect these changes and requirments. +// + +__drv_raisesIRQL(DISPATCH_LEVEL) +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +tapIrpCsqAcquireQueueLock( + __in PIO_CSQ Csq, + __out PKIRQL Irql + ) +{ + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ )Csq; + + // + // Suppressing because the address below csq is valid since it's + // part of TAP_ADAPTER_CONTEXT structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'") + KeAcquireSpinLock(&tapIrpCsq->QueueLock, Irql); +} + +// +// tapIrpCsqReleaseQueueLock modifies the execution level of the current processor. +// +// KeReleaseSpinLock assumes we already hold the spin lock and are therefore +// running at Dispatch level. It will use the Irql parameter saved in a +// previous call to KeAcquireSpinLock to return the thread back to it's original +// execution level. +// +// The annotations reflect these changes and requirments. +// + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +tapIrpCsqReleaseQueueLock( + __in PIO_CSQ Csq, + __in KIRQL Irql + ) +{ + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ )Csq; + + // + // Suppressing because the address below csq is valid since it's + // part of TAP_ADAPTER_CONTEXT structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'") + KeReleaseSpinLock(&tapIrpCsq->QueueLock, Irql); +} + +VOID +tapIrpCsqCompleteCanceledIrp( + __in PIO_CSQ pCsq, + __in PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(pCsq); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +VOID +tapIrpCsqInitialize( + __in PTAP_IRP_CSQ TapIrpCsq + ) +{ + KeInitializeSpinLock(&TapIrpCsq->QueueLock); + + NdisInitializeListHead(&TapIrpCsq->Queue); + + IoCsqInitialize( + &TapIrpCsq->CsqQueue, + tapIrpCsqInsert, + tapIrpCsqRemoveIrp, + tapIrpCsqPeekNextIrp, + tapIrpCsqAcquireQueueLock, + tapIrpCsqReleaseQueueLock, + tapIrpCsqCompleteCanceledIrp + ); +} + +VOID +tapIrpCsqFlush( + __in PTAP_IRP_CSQ TapIrpCsq + ) +{ + PIRP pendingIrp; + + // + // Flush the pending read IRP queue. + // + pendingIrp = IoCsqRemoveNextIrp( + &TapIrpCsq->CsqQueue, + NULL + ); + + while(pendingIrp) + { + // Cancel the IRP + pendingIrp->IoStatus.Information = 0; + pendingIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); + + pendingIrp = IoCsqRemoveNextIrp( + &TapIrpCsq->CsqQueue, + NULL + ); + } + + ASSERT(IsListEmpty(&TapIrpCsq->Queue)); +} diff --git a/windows/TapDriver6/mem.h b/windows/TapDriver6/mem.h new file mode 100644 index 00000000..a8359e19 --- /dev/null +++ b/windows/TapDriver6/mem.h @@ -0,0 +1,113 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//------------------ +// Memory Management +//------------------ + +PVOID +MemAlloc( + __in ULONG p_Size, + __in BOOLEAN zero + ); + +VOID +MemFree( + __in PVOID p_Addr, + __in ULONG p_Size + ); + +//====================================================================== +// TAP Packet Queue +//====================================================================== + +typedef +struct _TAP_PACKET +{ + LIST_ENTRY QueueLink; + +# define TAP_PACKET_SIZE(data_size) (sizeof (TAP_PACKET) + (data_size)) +# define TP_TUN 0x80000000 +# define TP_SIZE_MASK (~TP_TUN) + ULONG m_SizeFlags; + + // m_Data must be the last struct member + UCHAR m_Data []; +} TAP_PACKET, *PTAP_PACKET; + +#define TAP_PACKET_TAG '6PAT' // "TAP6" + +typedef struct _TAP_PACKET_QUEUE +{ + KSPIN_LOCK QueueLock; + LIST_ENTRY Queue; + ULONG Count; // Count of currently queued items + ULONG MaxCount; +} TAP_PACKET_QUEUE, *PTAP_PACKET_QUEUE; + +VOID +tapPacketQueueInsertTail( + __in PTAP_PACKET_QUEUE TapPacketQueue, + __in PTAP_PACKET TapPacket + ); + + +// Call with QueueLock held +PTAP_PACKET +tapPacketRemoveHeadLocked( + __in PTAP_PACKET_QUEUE TapPacketQueue + ); + +PTAP_PACKET +tapPacketRemoveHead( + __in PTAP_PACKET_QUEUE TapPacketQueue + ); + +VOID +tapPacketQueueInitialize( + __in PTAP_PACKET_QUEUE TapPacketQueue + ); + +//---------------------- +// Cancel-Safe IRP Queue +//---------------------- + +typedef struct _TAP_IRP_CSQ +{ + IO_CSQ CsqQueue; + KSPIN_LOCK QueueLock; + LIST_ENTRY Queue; + ULONG Count; // Count of currently queued items + ULONG MaxCount; +} TAP_IRP_CSQ, *PTAP_IRP_CSQ; + +VOID +tapIrpCsqInitialize( + __in PTAP_IRP_CSQ TapIrpCsq + ); + +VOID +tapIrpCsqFlush( + __in PTAP_IRP_CSQ TapIrpCsq + ); diff --git a/windows/TapDriver6/oidrequest.c b/windows/TapDriver6/oidrequest.c new file mode 100644 index 00000000..a6882f89 --- /dev/null +++ b/windows/TapDriver6/oidrequest.c @@ -0,0 +1,1028 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +#ifndef DBG + +#define DBG_PRINT_OID_NAME + +#else + +VOID +DBG_PRINT_OID_NAME( + __in NDIS_OID Oid + ) +{ + PCHAR oidName = NULL; + + switch (Oid){ + + #undef MAKECASE + #define MAKECASE(oidx) case oidx: oidName = #oidx "\n"; break; + + /* Operational OIDs */ + MAKECASE(OID_GEN_SUPPORTED_LIST) + MAKECASE(OID_GEN_HARDWARE_STATUS) + MAKECASE(OID_GEN_MEDIA_SUPPORTED) + MAKECASE(OID_GEN_MEDIA_IN_USE) + MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD) + MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE) + MAKECASE(OID_GEN_LINK_SPEED) + MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE) + MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE) + MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE) + MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE) + MAKECASE(OID_GEN_VENDOR_ID) + MAKECASE(OID_GEN_VENDOR_DESCRIPTION) + MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION) + MAKECASE(OID_GEN_CURRENT_PACKET_FILTER) + MAKECASE(OID_GEN_CURRENT_LOOKAHEAD) + MAKECASE(OID_GEN_DRIVER_VERSION) + MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE) + MAKECASE(OID_GEN_PROTOCOL_OPTIONS) + MAKECASE(OID_GEN_MAC_OPTIONS) + MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS) + MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS) + MAKECASE(OID_GEN_SUPPORTED_GUIDS) + MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES) + MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET) + MAKECASE(OID_GEN_MEDIA_CAPABILITIES) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM) + MAKECASE(OID_GEN_MACHINE_NAME) + MAKECASE(OID_GEN_VLAN_ID) + MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER) + + /* Operational OIDs for NDIS 6.0 */ + MAKECASE(OID_GEN_MAX_LINK_SPEED) + MAKECASE(OID_GEN_LINK_STATE) + MAKECASE(OID_GEN_LINK_PARAMETERS) + MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES) + MAKECASE(OID_GEN_ENUMERATE_PORTS) + MAKECASE(OID_GEN_PORT_STATE) + MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS) + MAKECASE(OID_GEN_INTERRUPT_MODERATION) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX) + + /* Statistical OIDs */ + MAKECASE(OID_GEN_XMIT_OK) + MAKECASE(OID_GEN_RCV_OK) + MAKECASE(OID_GEN_XMIT_ERROR) + MAKECASE(OID_GEN_RCV_ERROR) + MAKECASE(OID_GEN_RCV_NO_BUFFER) + MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT) + MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT) + MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT) + MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT) + MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT) + MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT) + MAKECASE(OID_GEN_DIRECTED_BYTES_RCV) + MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV) + MAKECASE(OID_GEN_MULTICAST_BYTES_RCV) + MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV) + MAKECASE(OID_GEN_BROADCAST_BYTES_RCV) + MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV) + MAKECASE(OID_GEN_RCV_CRC_ERROR) + MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH) + + /* Statistical OIDs for NDIS 6.0 */ + MAKECASE(OID_GEN_STATISTICS) + MAKECASE(OID_GEN_BYTES_RCV) + MAKECASE(OID_GEN_BYTES_XMIT) + MAKECASE(OID_GEN_RCV_DISCARDS) + MAKECASE(OID_GEN_XMIT_DISCARDS) + + /* Misc OIDs */ + MAKECASE(OID_GEN_GET_TIME_CAPS) + MAKECASE(OID_GEN_GET_NETCARD_TIME) + MAKECASE(OID_GEN_NETCARD_LOAD) + MAKECASE(OID_GEN_DEVICE_PROFILE) + MAKECASE(OID_GEN_INIT_TIME_MS) + MAKECASE(OID_GEN_RESET_COUNTS) + MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS) + + /* PnP power management operational OIDs */ + MAKECASE(OID_PNP_CAPABILITIES) + MAKECASE(OID_PNP_SET_POWER) + MAKECASE(OID_PNP_QUERY_POWER) + MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_ENABLE_WAKE_UP) + MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST) + + /* PnP power management statistical OIDs */ + MAKECASE(OID_PNP_WAKE_UP_ERROR) + MAKECASE(OID_PNP_WAKE_UP_OK) + + /* Ethernet operational OIDs */ + MAKECASE(OID_802_3_PERMANENT_ADDRESS) + MAKECASE(OID_802_3_CURRENT_ADDRESS) + MAKECASE(OID_802_3_MULTICAST_LIST) + MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE) + MAKECASE(OID_802_3_MAC_OPTIONS) + + /* Ethernet operational OIDs for NDIS 6.0 */ + MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS) + MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS) + + /* Ethernet statistical OIDs */ + MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT) + MAKECASE(OID_802_3_XMIT_ONE_COLLISION) + MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS) + MAKECASE(OID_802_3_XMIT_DEFERRED) + MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS) + MAKECASE(OID_802_3_RCV_OVERRUN) + MAKECASE(OID_802_3_XMIT_UNDERRUN) + MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE) + MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST) + MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS) + + /* TCP/IP OIDs */ + MAKECASE(OID_TCP_TASK_OFFLOAD) + MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA) + MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA) + MAKECASE(OID_TCP_SAN_SUPPORT) + MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA) + MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA) + MAKECASE(OID_TCP4_OFFLOAD_STATS) + MAKECASE(OID_TCP6_OFFLOAD_STATS) + MAKECASE(OID_IP4_OFFLOAD_STATS) + MAKECASE(OID_IP6_OFFLOAD_STATS) + + /* TCP offload OIDs for NDIS 6 */ + MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG) + MAKECASE(OID_TCP_OFFLOAD_PARAMETERS) + MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) + MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG) + MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES) + MAKECASE(OID_OFFLOAD_ENCAPSULATION) + +#if (NDIS_SUPPORT_NDIS620) + /* VMQ OIDs for NDIS 6.20 */ + MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE) + MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER) + MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE) + MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE) + MAKECASE(OID_RECEIVE_FILTER_SET_FILTER) +#endif + +#if (NDIS_SUPPORT_NDIS630) + /* NDIS QoS OIDs for NDIS 6.30 */ + MAKECASE(OID_QOS_PARAMETERS) +#endif + } + + if (oidName) + { + DEBUGP(("OID: %s", oidName)); + } + else + { + DEBUGP(("<** Unknown OID 0x%08x **>\n", Oid)); + } +} + +#endif // DBG + +//====================================================================== +// TAP NDIS 6 OID Request Callbacks +//====================================================================== + +NDIS_STATUS +tapSetMulticastList( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNDIS_OID_REQUEST OidRequest + ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + // + // Initialize. + // + OidRequest->DATA.SET_INFORMATION.BytesNeeded = MACADDR_SIZE; + OidRequest->DATA.SET_INFORMATION.BytesRead + = OidRequest->DATA.SET_INFORMATION.InformationBufferLength; + + + do + { + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength % MACADDR_SIZE) + { + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength > (TAP_MAX_MCAST_LIST * MACADDR_SIZE)) + { + status = NDIS_STATUS_MULTICAST_FULL; + OidRequest->DATA.SET_INFORMATION.BytesNeeded = TAP_MAX_MCAST_LIST * MACADDR_SIZE; + break; + } + + // BUGBUG!!! Is lock needed??? If so, use NDIS_RW_LOCK. Also apply to packet filter. + + NdisZeroMemory(Adapter->MCList, + TAP_MAX_MCAST_LIST * MACADDR_SIZE); + + NdisMoveMemory(Adapter->MCList, + OidRequest->DATA.SET_INFORMATION.InformationBuffer, + OidRequest->DATA.SET_INFORMATION.InformationBufferLength); + + Adapter->ulMCListSize = OidRequest->DATA.SET_INFORMATION.InformationBufferLength / MACADDR_SIZE; + + } while(FALSE); + return status; +} + +NDIS_STATUS +tapSetPacketFilter( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in ULONG PacketFilter + ) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + // any bits not supported? + if (PacketFilter & ~(TAP_SUPPORTED_FILTERS)) + { + DEBUGP (("[TAP] Unsupported packet filter: 0x%08x\n", PacketFilter)); + status = NDIS_STATUS_NOT_SUPPORTED; + } + else + { + // Any actual filtering changes? + if (PacketFilter != Adapter->PacketFilter) + { + // + // Change the filtering modes on hardware + // + + // Save the new packet filter value + Adapter->PacketFilter = PacketFilter; + } + } + + return status; +} + +NDIS_STATUS +AdapterSetPowerD0( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +/*++ +Routine Description: + + NIC power has been restored to the working power state (D0). + Prepare the NIC for normal operation: + - Restore hardware context (packet filters, multicast addresses, MAC address, etc.) + - Enable interrupts and the NIC's DMA engine. + +Arguments: + + Adapter - Pointer to adapter block + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DEBUGP (("[TAP] PowerState: Fully powered\n")); + + // Start data path... + + return status; +} + +NDIS_STATUS +AdapterSetPowerLow( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in NDIS_DEVICE_POWER_STATE PowerState + ) +/*++ +Routine Description: + + The NIC is about to be transitioned to a low power state. + Prepare the NIC for the sleeping state: + - Disable interrupts and the NIC's DMA engine, cancel timers. + - Save any hardware context that the NIC cannot preserve in + a sleeping state (packet filters, multicast addresses, + the current MAC address, etc.) + A miniport driver cannot access the NIC hardware after + the NIC has been set to the D3 state by the bus driver. + + Miniport drivers NDIS v6.30 and above + Do NOT wait for NDIS to return the ownership of all + NBLs from outstanding receive indications + Retain ownership of all the receive descriptors and + packet buffers previously owned by the hardware. + +Arguments: + + Adapter - Pointer to adapter block + PowerState - New power state + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DEBUGP (("[TAP] PowerState: Low-power\n")); + + // + // Miniport drivers NDIS v6.20 and below are + // paused prior the low power transition + // + + // Check for paused state... + // Verify data path stopped... + + return status; +} + +NDIS_STATUS +tapSetInformation( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNDIS_OID_REQUEST OidRequest + ) +/*++ + +Routine Description: + + Helper function to perform a set OID request + +Arguments: + + Adapter - + NdisSetRequest - The OID to set + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DBG_PRINT_OID_NAME(OidRequest->DATA.SET_INFORMATION.Oid); + + switch(OidRequest->DATA.SET_INFORMATION.Oid) + { + case OID_802_3_MULTICAST_LIST: + // + // Set the multicast address list on the NIC for packet reception. + // The NIC driver can set a limit on the number of multicast + // addresses bound protocol drivers can enable simultaneously. + // NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver + // exceeds this limit or if it specifies an invalid multicast + // address. + // + status = tapSetMulticastList(Adapter,OidRequest); + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + // + // A protocol driver can set a suggested value for the number + // of bytes to be used in its binding; however, the underlying + // NIC driver is never required to limit its indications to + // the value set. + // + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG)) + { + OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG); + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + Adapter->ulLookahead = *(PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer; + + OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG); + status = NDIS_STATUS_SUCCESS; + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + // + // Program the hardware to indicate the packets + // of certain filter types. + // + if(OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG)) + { + OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG); + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + OidRequest->DATA.SET_INFORMATION.BytesRead + = OidRequest->DATA.SET_INFORMATION.InformationBufferLength; + + status = tapSetPacketFilter( + Adapter, + *((PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer) + ); + + break; + + case OID_PNP_SET_POWER: + { + // Sanity check. + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength + < sizeof(NDIS_DEVICE_POWER_STATE) + ) + { + status = NDIS_STATUS_INVALID_LENGTH; + } + else + { + NDIS_DEVICE_POWER_STATE PowerState; + + PowerState = *(PNDIS_DEVICE_POWER_STATE UNALIGNED)OidRequest->DATA.SET_INFORMATION.InformationBuffer; + OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE); + + if(PowerState < NdisDeviceStateD0 || + PowerState > NdisDeviceStateD3) + { + status = NDIS_STATUS_INVALID_DATA; + } + else + { + Adapter->CurrentPowerState = PowerState; + + if (PowerState == NdisDeviceStateD0) + { + status = AdapterSetPowerD0(Adapter); + } + else + { + status = AdapterSetPowerLow(Adapter, PowerState); + } + } + } + } + break; + +#if (NDIS_SUPPORT_NDIS61) + case OID_PNP_ADD_WAKE_UP_PATTERN: + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + case OID_PNP_ENABLE_WAKE_UP: +#endif + ASSERT(!"NIC does not support wake on LAN OIDs"); + default: + // + // The entry point may by used by other requests + // + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + return status; +} + +NDIS_STATUS +tapQueryInformation( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNDIS_OID_REQUEST OidRequest + ) +/*++ + +Routine Description: + + Helper function to perform a query OID request + +Arguments: + + Adapter - + OidRequest - The OID request that is being queried + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + NDIS_MEDIUM Medium = TAP_MEDIUM_TYPE; + NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; + UCHAR VendorDesc[] = TAP_VENDOR_DESC; + ULONG ulInfo; + USHORT usInfo; + ULONG64 ulInfo64; + + // Default to returning the ULONG value + PVOID pInfo=NULL; + ULONG ulInfoLen = sizeof(ulInfo); + + // ATTENTION!!! Ignore OIDs to noisy to print... + if((OidRequest->DATA.QUERY_INFORMATION.Oid != OID_GEN_STATISTICS) + && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP4_OFFLOAD_STATS) + && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP6_OFFLOAD_STATS) + ) + { + DBG_PRINT_OID_NAME(OidRequest->DATA.QUERY_INFORMATION.Oid); + } + + // Dispatch based on object identifier (OID). + switch(OidRequest->DATA.QUERY_INFORMATION.Oid) + { + case OID_GEN_HARDWARE_STATUS: + // + // Specify the current hardware status of the underlying NIC as + // one of the following NDIS_HARDWARE_STATUS-type values. + // + pInfo = (PVOID) &HardwareStatus; + ulInfoLen = sizeof(NDIS_HARDWARE_STATUS); + break; + + case OID_802_3_PERMANENT_ADDRESS: + // + // Return the MAC address of the NIC burnt in the hardware. + // + pInfo = Adapter->PermanentAddress; + ulInfoLen = MACADDR_SIZE; + break; + + case OID_802_3_CURRENT_ADDRESS: + // + // Return the MAC address the NIC is currently programmed to + // use. Note that this address could be different from the + // permananent address as the user can override using + // registry. Read NdisReadNetworkAddress doc for more info. + // + pInfo = Adapter->CurrentAddress; + ulInfoLen = MACADDR_SIZE; + break; + + case OID_GEN_MEDIA_SUPPORTED: + // + // Return an array of media that are supported by the miniport. + // This miniport only supports one medium (Ethernet), so the OID + // returns identical results to OID_GEN_MEDIA_IN_USE. + // + + __fallthrough; + + case OID_GEN_MEDIA_IN_USE: + // + // Return an array of media that are currently in use by the + // miniport. This array should be a subset of the array returned + // by OID_GEN_MEDIA_SUPPORTED. + // + pInfo = &Medium; + ulInfoLen = sizeof(Medium); + break; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + // + // Specify the maximum total packet length, in bytes, the NIC + // supports including the header. A protocol driver might use + // this returned length as a gauge to determine the maximum + // size packet that a NIC driver could forward to the + // protocol driver. The miniport driver must never indicate + // up to the bound protocol driver packets received over the + // network that are longer than the packet size specified by + // OID_GEN_MAXIMUM_TOTAL_SIZE. + // + + __fallthrough; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + // + // The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum + // number of bytes that a single net packet occupies in the + // transmit buffer space of the NIC. In our case, the transmit + // block size is identical to its maximum packet size. + __fallthrough; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + // + // The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of + // storage, in bytes, that a single packet occupies in the receive + // buffer space of the NIC. + // + ulInfo = (ULONG) TAP_MAX_FRAME_SIZE; + pInfo = &ulInfo; + break; + + case OID_GEN_INTERRUPT_MODERATION: + { + PNDIS_INTERRUPT_MODERATION_PARAMETERS moderationParams + = (PNDIS_INTERRUPT_MODERATION_PARAMETERS)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer; + + moderationParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + moderationParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + moderationParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + moderationParams->Flags = 0; + moderationParams->InterruptModeration = NdisInterruptModerationNotSupported; + ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + } + break; + + case OID_PNP_QUERY_POWER: + // Simply succeed this. + break; + + case OID_GEN_VENDOR_ID: + // + // Specify a three-byte IEEE-registered vendor code, followed + // by a single byte that the vendor assigns to identify a + // particular NIC. The IEEE code uniquely identifies the vendor + // and is the same as the three bytes appearing at the beginning + // of the NIC hardware address. Vendors without an IEEE-registered + // code should use the value 0xFFFFFF. + // + + ulInfo = TAP_VENDOR_ID; + pInfo = &ulInfo; + break; + + case OID_GEN_VENDOR_DESCRIPTION: + // + // Specify a zero-terminated string describing the NIC vendor. + // + pInfo = VendorDesc; + ulInfoLen = sizeof(VendorDesc); + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + // + // Specify the vendor-assigned version number of the NIC driver. + // The low-order half of the return value specifies the minor + // version; the high-order half specifies the major version. + // + + ulInfo = TAP_DRIVER_VENDOR_VERSION; + pInfo = &ulInfo; + break; + + case OID_GEN_DRIVER_VERSION: + // + // Specify the NDIS version in use by the NIC driver. The high + // byte is the major version number; the low byte is the minor + // version number. + // + usInfo = (USHORT) (TAP_NDIS_MAJOR_VERSION<<8) + TAP_NDIS_MINOR_VERSION; + pInfo = (PVOID) &usInfo; + ulInfoLen = sizeof(USHORT); + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + // + // The maximum number of multicast addresses the NIC driver + // can manage. This list is global for all protocols bound + // to (or above) the NIC. Consequently, a protocol can receive + // NDIS_STATUS_MULTICAST_FULL from the NIC driver when + // attempting to set the multicast address list, even if + // the number of elements in the given list is less than + // the number originally returned for this query. + // + + ulInfo = TAP_MAX_MCAST_LIST; + pInfo = &ulInfo; + break; + + case OID_GEN_XMIT_ERROR: + ulInfo = (ULONG) + (Adapter->TxAbortExcessCollisions + + Adapter->TxDmaUnderrun + + Adapter->TxLostCRS + + Adapter->TxLateCollisions+ + Adapter->TransmitFailuresOther); + pInfo = &ulInfo; + break; + + case OID_GEN_RCV_ERROR: + ulInfo = (ULONG) + (Adapter->RxCrcErrors + + Adapter->RxAlignmentErrors + + Adapter->RxDmaOverrunErrors + + Adapter->RxRuntErrors); + pInfo = &ulInfo; + break; + + case OID_GEN_RCV_DISCARDS: + ulInfo = (ULONG)Adapter->RxResourceErrors; + pInfo = &ulInfo; + break; + + case OID_GEN_RCV_NO_BUFFER: + ulInfo = (ULONG)Adapter->RxResourceErrors; + pInfo = &ulInfo; + break; + + case OID_GEN_XMIT_OK: + ulInfo64 = Adapter->FramesTxBroadcast + + Adapter->FramesTxMulticast + + Adapter->FramesTxDirected; + pInfo = &ulInfo64; + if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) || + OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0) + { + ulInfoLen = sizeof(ULONG64); + } + else + { + ulInfoLen = sizeof(ULONG); + } + + // We should always report that only 8 bytes are required to keep ndistest happy + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); + break; + + case OID_GEN_RCV_OK: + ulInfo64 = Adapter->FramesRxBroadcast + + Adapter->FramesRxMulticast + + Adapter->FramesRxDirected; + + pInfo = &ulInfo64; + + if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) || + OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0) + { + ulInfoLen = sizeof(ULONG64); + } + else + { + ulInfoLen = sizeof(ULONG); + } + + // We should always report that only 8 bytes are required to keep ndistest happy + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + + ulInfo = Adapter->RxAlignmentErrors; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_ONE_COLLISION: + + ulInfo = Adapter->OneRetry; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + + ulInfo = Adapter->MoreThanOneRetry; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_DEFERRED: + + ulInfo = Adapter->TxOKButDeferred; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_MAX_COLLISIONS: + + ulInfo = Adapter->TxAbortExcessCollisions; + pInfo = &ulInfo; + break; + + case OID_802_3_RCV_OVERRUN: + + ulInfo = Adapter->RxDmaOverrunErrors; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_UNDERRUN: + + ulInfo = Adapter->TxDmaUnderrun; + pInfo = &ulInfo; + break; + + case OID_GEN_STATISTICS: + + if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(NDIS_STATISTICS_INFO)) + { + status = NDIS_STATUS_INVALID_LENGTH; + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(NDIS_STATISTICS_INFO); + break; + } + else + { + PNDIS_STATISTICS_INFO Statistics + = (PNDIS_STATISTICS_INFO)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer; + + {C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1);} + Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; + Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1; + + Statistics->SupportedStatistics = TAP_SUPPORTED_STATISTICS; + + /* Bytes in */ + Statistics->ifHCInOctets = + Adapter->BytesRxDirected + + Adapter->BytesRxMulticast + + Adapter->BytesRxBroadcast; + + Statistics->ifHCInUcastOctets = + Adapter->BytesRxDirected; + + Statistics->ifHCInMulticastOctets = + Adapter->BytesRxMulticast; + + Statistics->ifHCInBroadcastOctets = + Adapter->BytesRxBroadcast; + + /* Packets in */ + Statistics->ifHCInUcastPkts = + Adapter->FramesRxDirected; + + Statistics->ifHCInMulticastPkts = + Adapter->FramesRxMulticast; + + Statistics->ifHCInBroadcastPkts = + Adapter->FramesRxBroadcast; + + /* Errors in */ + Statistics->ifInErrors = + Adapter->RxCrcErrors + + Adapter->RxAlignmentErrors + + Adapter->RxDmaOverrunErrors + + Adapter->RxRuntErrors; + + Statistics->ifInDiscards = + Adapter->RxResourceErrors; + + + /* Bytes out */ + Statistics->ifHCOutOctets = + Adapter->BytesTxDirected + + Adapter->BytesTxMulticast + + Adapter->BytesTxBroadcast; + + Statistics->ifHCOutUcastOctets = + Adapter->BytesTxDirected; + + Statistics->ifHCOutMulticastOctets = + Adapter->BytesTxMulticast; + + Statistics->ifHCOutBroadcastOctets = + Adapter->BytesTxBroadcast; + + /* Packets out */ + Statistics->ifHCOutUcastPkts = + Adapter->FramesTxDirected; + + Statistics->ifHCOutMulticastPkts = + Adapter->FramesTxMulticast; + + Statistics->ifHCOutBroadcastPkts = + Adapter->FramesTxBroadcast; + + /* Errors out */ + Statistics->ifOutErrors = + Adapter->TxAbortExcessCollisions + + Adapter->TxDmaUnderrun + + Adapter->TxLostCRS + + Adapter->TxLateCollisions+ + Adapter->TransmitFailuresOther; + + Statistics->ifOutDiscards = 0ULL; + + ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; + } + + break; + + // TODO: Inplement these query information requests. + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_MAXIMUM_SEND_PACKETS: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_802_3_XMIT_LATE_COLLISIONS: + + default: + // + // The entry point may by used by other requests + // + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (status == NDIS_STATUS_SUCCESS) + { + ASSERT(ulInfoLen > 0); + + if (ulInfoLen <= OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength) + { + if(pInfo) + { + // Copy result into InformationBuffer + NdisMoveMemory( + OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, + pInfo, + ulInfoLen + ); + } + + OidRequest->DATA.QUERY_INFORMATION.BytesWritten = ulInfoLen; + } + else + { + // too short + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = ulInfoLen; + status = NDIS_STATUS_BUFFER_TOO_SHORT; + } + } + + return status; +} + +NDIS_STATUS +AdapterOidRequest( + __in NDIS_HANDLE MiniportAdapterContext, + __in PNDIS_OID_REQUEST OidRequest + ) +/*++ + +Routine Description: + + Entry point called by NDIS to get or set the value of a specified OID. + +Arguments: + + MiniportAdapterContext - Our adapter handle + NdisRequest - The OID request to handle + +Return Value: + + Return code from the NdisRequest below. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + NDIS_STATUS status; + + // Dispatch based on request type. + switch (OidRequest->RequestType) + { + case NdisRequestSetInformation: + status = tapSetInformation(adapter,OidRequest); + break; + + case NdisRequestQueryInformation: + case NdisRequestQueryStatistics: + status = tapQueryInformation(adapter,OidRequest); + break; + + case NdisRequestMethod: // TAP doesn't need to respond to this request type. + default: + // + // The entry point may by used by other requests + // + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + return status; +} + +VOID +AdapterCancelOidRequest( + __in NDIS_HANDLE MiniportAdapterContext, + __in PVOID RequestId + ) +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + + UNREFERENCED_PARAMETER(RequestId); + + // + // This miniport sample does not pend any OID requests, so we don't have + // to worry about cancelling them. + // +} + diff --git a/windows/TapDriver6/proto.h b/windows/TapDriver6/proto.h new file mode 100644 index 00000000..cc23de6d --- /dev/null +++ b/windows/TapDriver6/proto.h @@ -0,0 +1,224 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//============================================================ +// MAC address, Ethernet header, and ARP +//============================================================ + +#pragma pack(1) + +#define IP_HEADER_SIZE 20 +#define IPV6_HEADER_SIZE 40 + +#define MACADDR_SIZE 6 +typedef unsigned char MACADDR[MACADDR_SIZE]; + +typedef unsigned long IPADDR; +typedef unsigned char IPV6ADDR[16]; + +//----------------- +// Ethernet address +//----------------- + +typedef struct { + MACADDR addr; +} ETH_ADDR; + +typedef struct { + ETH_ADDR list[TAP_MAX_MCAST_LIST]; +} MC_LIST; + + +// BUGBUG!!! Consider using ststem defines in netiodef.h!!! + +//---------------- +// Ethernet header +//---------------- +typedef struct +{ + MACADDR dest; /* destination eth addr */ + MACADDR src; /* source ether addr */ + USHORT proto; /* packet type ID field */ +} ETH_HEADER, *PETH_HEADER; + +//---------------- +// ARP packet +//---------------- + +typedef struct + { + MACADDR m_MAC_Destination; // Reverse these two + MACADDR m_MAC_Source; // to answer ARP requests + USHORT m_Proto; // 0x0806 + +# define MAC_ADDR_TYPE 0x0001 + USHORT m_MAC_AddressType; // 0x0001 + + USHORT m_PROTO_AddressType; // 0x0800 + UCHAR m_MAC_AddressSize; // 0x06 + UCHAR m_PROTO_AddressSize; // 0x04 + +# define ARP_REQUEST 0x0001 +# define ARP_REPLY 0x0002 + USHORT m_ARP_Operation; // 0x0001 for ARP request, 0x0002 for ARP reply + + MACADDR m_ARP_MAC_Source; + IPADDR m_ARP_IP_Source; + MACADDR m_ARP_MAC_Destination; + IPADDR m_ARP_IP_Destination; + } +ARP_PACKET, *PARP_PACKET; + +//---------- +// IP Header +//---------- + +typedef struct { +# define IPH_GET_VER(v) (((v) >> 4) & 0x0F) +# define IPH_GET_LEN(v) (((v) & 0x0F) << 2) + UCHAR version_len; + + UCHAR tos; + USHORT tot_len; + USHORT id; + +# define IP_OFFMASK 0x1fff + USHORT frag_off; + + UCHAR ttl; + +# define IPPROTO_UDP 17 /* UDP protocol */ +# define IPPROTO_TCP 6 /* TCP protocol */ +# define IPPROTO_ICMP 1 /* ICMP protocol */ +# define IPPROTO_IGMP 2 /* IGMP protocol */ + UCHAR protocol; + + USHORT check; + ULONG saddr; + ULONG daddr; + /* The options start here. */ +} IPHDR; + +//----------- +// UDP header +//----------- + +typedef struct { + USHORT source; + USHORT dest; + USHORT len; + USHORT check; +} UDPHDR; + +//-------------------------- +// TCP header, per RFC 793. +//-------------------------- + +typedef struct { + USHORT source; /* source port */ + USHORT dest; /* destination port */ + ULONG seq; /* sequence number */ + ULONG ack_seq; /* acknowledgement number */ + +# define TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2) + UCHAR doff_res; + +# define TCPH_FIN_MASK (1<<0) +# define TCPH_SYN_MASK (1<<1) +# define TCPH_RST_MASK (1<<2) +# define TCPH_PSH_MASK (1<<3) +# define TCPH_ACK_MASK (1<<4) +# define TCPH_URG_MASK (1<<5) +# define TCPH_ECE_MASK (1<<6) +# define TCPH_CWR_MASK (1<<7) + UCHAR flags; + + USHORT window; + USHORT check; + USHORT urg_ptr; +} TCPHDR; + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 + +//------------ +// IPv6 Header +//------------ + +typedef struct { + UCHAR version_prio; + UCHAR flow_lbl[3]; + USHORT payload_len; +# define IPPROTO_ICMPV6 0x3a /* ICMP protocol v6 */ + UCHAR nexthdr; + UCHAR hop_limit; + IPV6ADDR saddr; + IPV6ADDR daddr; +} IPV6HDR; + +//-------------------------------------------- +// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861) +//-------------------------------------------- + +// Neighbor Solictiation - RFC 4861, 4.3 +// (this is just the ICMPv6 part of the packet) +typedef struct { + UCHAR type; +# define ICMPV6_TYPE_NS 135 // neighbour solicitation + UCHAR code; +# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA + USHORT checksum; + ULONG reserved; + IPV6ADDR target_addr; +} ICMPV6_NS; + +// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1 +// (this is just the ICMPv6 payload) +typedef struct { + UCHAR type; +# define ICMPV6_TYPE_NA 136 // neighbour advertisement + UCHAR code; +# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA + USHORT checksum; + UCHAR rso_bits; // Router(0), Solicited(2), Ovrrd(4) + UCHAR reserved[3]; + IPV6ADDR target_addr; +// always include "Target Link-layer Address" option (RFC 4861 4.6.1) + UCHAR opt_type; +#define ICMPV6_OPTION_TLLA 2 + UCHAR opt_length; +#define ICMPV6_LENGTH_TLLA 1 // multiplied by 8 -> 1 = 8 bytes + MACADDR target_macaddr; +} ICMPV6_NA; + +// this is the complete packet with Ethernet and IPv6 headers +typedef struct { + ETH_HEADER eth; + IPV6HDR ipv6; + ICMPV6_NA icmpv6; +} ICMPV6_NA_PKT; + +#pragma pack() diff --git a/windows/TapDriver6/prototypes.h b/windows/TapDriver6/prototypes.h new file mode 100644 index 00000000..a48d35e7 --- /dev/null +++ b/windows/TapDriver6/prototypes.h @@ -0,0 +1,91 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TAP_PROTOTYPES_DEFINED +#define TAP_PROTOTYPES_DEFINED + +DRIVER_INITIALIZE DriverEntry; + +//VOID AdapterFreeResources +// ( +// TapAdapterPointer p_Adapter +// ); +// + +// +//NTSTATUS TapDeviceHook +// ( +// IN PDEVICE_OBJECT p_DeviceObject, +// IN PIRP p_IRP +// ); +// + +NDIS_STATUS +CreateTapDevice( + __in PTAP_ADAPTER_CONTEXT Adapter + ); + +VOID +DestroyTapDevice( + __in PTAP_ADAPTER_CONTEXT Adapter + ); + +// Flush the pending send TAP packet queue. +VOID +tapFlushSendPacketQueue( + __in PTAP_ADAPTER_CONTEXT Adapter + ); + +VOID +IndicateReceivePacket( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PUCHAR packetData, + __in const unsigned int packetLength + ); + +/* +BOOLEAN +ProcessDHCP( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in const ETH_HEADER *eth, + __in const IPHDR *ip, + __in const UDPHDR *udp, + __in const DHCP *dhcp, + __in int optlen + ); +*/ + +/* +BOOLEAN +ProcessARP( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in const PARP_PACKET src, + __in const IPADDR adapter_ip, + __in const IPADDR ip_network, + __in const IPADDR ip_netmask, + __in const MACADDR mac + ); +*/ + +#endif diff --git a/windows/TapDriver6/resource.h b/windows/TapDriver6/resource.h new file mode 100644 index 00000000..d609f17c --- /dev/null +++ b/windows/TapDriver6/resource.h @@ -0,0 +1,1573 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define SW_HIDE 0 +#define HIDE_WINDOW 0 +#define WM_NULL 0x0000 +#define WA_INACTIVE 0 +#define HTNOWHERE 0 +#define SMTO_NORMAL 0x0000 +#define ICON_SMALL 0 +#define SIZE_RESTORED 0 +#define BN_CLICKED 0 +#define BST_UNCHECKED 0x0000 +#define HDS_HORZ 0x0000 +#define TBSTYLE_BUTTON 0x0000 +#define TBS_HORZ 0x0000 +#define TBS_BOTTOM 0x0000 +#define TBS_RIGHT 0x0000 +#define LVS_ICON 0x0000 +#define LVS_ALIGNTOP 0x0000 +#define TCS_TABS 0x0000 +#define TCS_SINGLELINE 0x0000 +#define TCS_RIGHTJUSTIFY 0x0000 +#define DTS_SHORTDATEFORMAT 0x0000 +#define PGS_VERT 0x00000000 +#define LANG_NEUTRAL 0x00 +#define SUBLANG_NEUTRAL 0x00 +#define SORT_DEFAULT 0x0 +#define SORT_JAPANESE_XJIS 0x0 +#define SORT_CHINESE_BIG5 0x0 +#define SORT_CHINESE_PRCP 0x0 +#define SORT_KOREAN_KSC 0x0 +#define SORT_HUNGARIAN_DEFAULT 0x0 +#define SORT_GEORGIAN_TRADITIONAL 0x0 +#define _USE_DECLSPECS_FOR_SAL 0 +#define _USE_ATTRIBUTES_FOR_SAL 0 +#define __drv_typeConst 0 +#define VER_DEBUG 0 +#define VER_PRERELEASE 0 +#define PRODUCT_TAP_WIN_MINOR 0 +#define WINAPI_PARTITION_DESKTOP 0x00000001 +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 +#define SW_SHOWNORMAL 1 +#define SW_NORMAL 1 +#define SHOW_OPENWINDOW 1 +#define SW_PARENTCLOSING 1 +#define VK_LBUTTON 0x01 +#define WM_CREATE 0x0001 +#define WA_ACTIVE 1 +#define PWR_OK 1 +#define PWR_SUSPENDREQUEST 1 +#define NFR_ANSI 1 +#define UIS_SET 1 +#define UISF_HIDEFOCUS 0x1 +#define XBUTTON1 0x0001 +#define WMSZ_LEFT 1 +#define HTCLIENT 1 +#define SMTO_BLOCK 0x0001 +#define MA_ACTIVATE 1 +#define ICON_BIG 1 +#define SIZE_MINIMIZED 1 +#define MK_LBUTTON 0x0001 +#define TME_HOVER 0x00000001 +#define CS_VREDRAW 0x0001 +#define CF_TEXT 1 +#define SCF_ISSECURE 0x00000001 +#define IDOK 1 +#define BN_PAINT 1 +#define BST_CHECKED 0x0001 +#define TBSTYLE_SEP 0x0001 +#define TTS_ALWAYSTIP 0x01 +#define TBS_AUTOTICKS 0x0001 +#define UDS_WRAP 0x0001 +#define PBS_SMOOTH 0x01 +#define LWS_TRANSPARENT 0x0001 +#define LVS_REPORT 0x0001 +#define TVS_HASBUTTONS 0x0001 +#define TVS_EX_NOSINGLECOLLAPSE 0x0001 +#define TCS_SCROLLOPPOSITE 0x0001 +#define ACS_CENTER 0x0001 +#define MCS_DAYSTATE 0x0001 +#define DTS_UPDOWN 0x0001 +#define PGS_HORZ 0x00000001 +#define NFS_EDIT 0x0001 +#define BCSIF_GLYPH 0x0001 +#define BCSS_NOSPLIT 0x0001 +#define LANG_ARABIC 0x01 +#define SUBLANG_DEFAULT 0x01 +#define SUBLANG_AFRIKAANS_SOUTH_AFRICA 0x01 +#define SUBLANG_ALBANIAN_ALBANIA 0x01 +#define SUBLANG_ALSATIAN_FRANCE 0x01 +#define SUBLANG_AMHARIC_ETHIOPIA 0x01 +#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 +#define SUBLANG_ARMENIAN_ARMENIA 0x01 +#define SUBLANG_ASSAMESE_INDIA 0x01 +#define SUBLANG_AZERI_LATIN 0x01 +#define SUBLANG_AZERBAIJANI_AZERBAIJAN_LATIN 0x01 +#define SUBLANG_BANGLA_INDIA 0x01 +#define SUBLANG_BASHKIR_RUSSIA 0x01 +#define SUBLANG_BASQUE_BASQUE 0x01 +#define SUBLANG_BELARUSIAN_BELARUS 0x01 +#define SUBLANG_BENGALI_INDIA 0x01 +#define SUBLANG_BRETON_FRANCE 0x01 +#define SUBLANG_BULGARIAN_BULGARIA 0x01 +#define SUBLANG_CATALAN_CATALAN 0x01 +#define SUBLANG_CENTRAL_KURDISH_IRAQ 0x01 +#define SUBLANG_CHEROKEE_CHEROKEE 0x01 +#define SUBLANG_CHINESE_TRADITIONAL 0x01 +#define SUBLANG_CORSICAN_FRANCE 0x01 +#define SUBLANG_CZECH_CZECH_REPUBLIC 0x01 +#define SUBLANG_CROATIAN_CROATIA 0x01 +#define SUBLANG_DANISH_DENMARK 0x01 +#define SUBLANG_DARI_AFGHANISTAN 0x01 +#define SUBLANG_DIVEHI_MALDIVES 0x01 +#define SUBLANG_DUTCH 0x01 +#define SUBLANG_ENGLISH_US 0x01 +#define SUBLANG_ESTONIAN_ESTONIA 0x01 +#define SUBLANG_FAEROESE_FAROE_ISLANDS 0x01 +#define SUBLANG_FILIPINO_PHILIPPINES 0x01 +#define SUBLANG_FINNISH_FINLAND 0x01 +#define SUBLANG_FRENCH 0x01 +#define SUBLANG_FRISIAN_NETHERLANDS 0x01 +#define SUBLANG_GALICIAN_GALICIAN 0x01 +#define SUBLANG_GEORGIAN_GEORGIA 0x01 +#define SUBLANG_GERMAN 0x01 +#define SUBLANG_GREEK_GREECE 0x01 +#define SUBLANG_GREENLANDIC_GREENLAND 0x01 +#define SUBLANG_GUJARATI_INDIA 0x01 +#define SUBLANG_HAUSA_NIGERIA_LATIN 0x01 +#define SUBLANG_HAWAIIAN_US 0x01 +#define SUBLANG_HEBREW_ISRAEL 0x01 +#define SUBLANG_HINDI_INDIA 0x01 +#define SUBLANG_HUNGARIAN_HUNGARY 0x01 +#define SUBLANG_ICELANDIC_ICELAND 0x01 +#define SUBLANG_IGBO_NIGERIA 0x01 +#define SUBLANG_INDONESIAN_INDONESIA 0x01 +#define SUBLANG_INUKTITUT_CANADA 0x01 +#define SUBLANG_ITALIAN 0x01 +#define SUBLANG_JAPANESE_JAPAN 0x01 +#define SUBLANG_KANNADA_INDIA 0x01 +#define SUBLANG_KAZAK_KAZAKHSTAN 0x01 +#define SUBLANG_KHMER_CAMBODIA 0x01 +#define SUBLANG_KICHE_GUATEMALA 0x01 +#define SUBLANG_KINYARWANDA_RWANDA 0x01 +#define SUBLANG_KONKANI_INDIA 0x01 +#define SUBLANG_KOREAN 0x01 +#define SUBLANG_KYRGYZ_KYRGYZSTAN 0x01 +#define SUBLANG_LAO_LAO 0x01 +#define SUBLANG_LATVIAN_LATVIA 0x01 +#define SUBLANG_LITHUANIAN 0x01 +#define SUBLANG_LUXEMBOURGISH_LUXEMBOURG 0x01 +#define SUBLANG_MACEDONIAN_MACEDONIA 0x01 +#define SUBLANG_MALAY_MALAYSIA 0x01 +#define SUBLANG_MALAYALAM_INDIA 0x01 +#define SUBLANG_MALTESE_MALTA 0x01 +#define SUBLANG_MAORI_NEW_ZEALAND 0x01 +#define SUBLANG_MAPUDUNGUN_CHILE 0x01 +#define SUBLANG_MARATHI_INDIA 0x01 +#define SUBLANG_MOHAWK_MOHAWK 0x01 +#define SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA 0x01 +#define SUBLANG_NEPALI_NEPAL 0x01 +#define SUBLANG_NORWEGIAN_BOKMAL 0x01 +#define SUBLANG_OCCITAN_FRANCE 0x01 +#define SUBLANG_ODIA_INDIA 0x01 +#define SUBLANG_ORIYA_INDIA 0x01 +#define SUBLANG_PASHTO_AFGHANISTAN 0x01 +#define SUBLANG_PERSIAN_IRAN 0x01 +#define SUBLANG_POLISH_POLAND 0x01 +#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 +#define SUBLANG_PUNJABI_INDIA 0x01 +#define SUBLANG_QUECHUA_BOLIVIA 0x01 +#define SUBLANG_ROMANIAN_ROMANIA 0x01 +#define SUBLANG_ROMANSH_SWITZERLAND 0x01 +#define SUBLANG_RUSSIAN_RUSSIA 0x01 +#define SUBLANG_SAKHA_RUSSIA 0x01 +#define SUBLANG_SAMI_NORTHERN_NORWAY 0x01 +#define SUBLANG_SANSKRIT_INDIA 0x01 +#define SUBLANG_SCOTTISH_GAELIC 0x01 +#define SUBLANG_SERBIAN_CROATIA 0x01 +#define SUBLANG_SINDHI_INDIA 0x01 +#define SUBLANG_SINHALESE_SRI_LANKA 0x01 +#define SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA 0x01 +#define SUBLANG_SLOVAK_SLOVAKIA 0x01 +#define SUBLANG_SLOVENIAN_SLOVENIA 0x01 +#define SUBLANG_SPANISH 0x01 +#define SUBLANG_SWAHILI_KENYA 0x01 +#define SUBLANG_SWEDISH 0x01 +#define SUBLANG_SYRIAC_SYRIA 0x01 +#define SUBLANG_TAJIK_TAJIKISTAN 0x01 +#define SUBLANG_TAMIL_INDIA 0x01 +#define SUBLANG_TATAR_RUSSIA 0x01 +#define SUBLANG_TELUGU_INDIA 0x01 +#define SUBLANG_THAI_THAILAND 0x01 +#define SUBLANG_TIBETAN_PRC 0x01 +#define SUBLANG_TIGRINYA_ETHIOPIA 0x01 +#define SUBLANG_TSWANA_SOUTH_AFRICA 0x01 +#define SUBLANG_TURKISH_TURKEY 0x01 +#define SUBLANG_TURKMEN_TURKMENISTAN 0x01 +#define SUBLANG_UIGHUR_PRC 0x01 +#define SUBLANG_UKRAINIAN_UKRAINE 0x01 +#define SUBLANG_UPPER_SORBIAN_GERMANY 0x01 +#define SUBLANG_URDU_PAKISTAN 0x01 +#define SUBLANG_UZBEK_LATIN 0x01 +#define SUBLANG_VIETNAMESE_VIETNAM 0x01 +#define SUBLANG_WELSH_UNITED_KINGDOM 0x01 +#define SUBLANG_WOLOF_SENEGAL 0x01 +#define SUBLANG_XHOSA_SOUTH_AFRICA 0x01 +#define SUBLANG_YAKUT_RUSSIA 0x01 +#define SUBLANG_YI_PRC 0x01 +#define SUBLANG_YORUBA_NIGERIA 0x01 +#define SUBLANG_ZULU_SOUTH_AFRICA 0x01 +#define SORT_INVARIANT_MATH 0x1 +#define SORT_JAPANESE_UNICODE 0x1 +#define SORT_CHINESE_UNICODE 0x1 +#define SORT_KOREAN_UNICODE 0x1 +#define SORT_GERMAN_PHONE_BOOK 0x1 +#define SORT_HUNGARIAN_TECHNICAL 0x1 +#define SORT_GEORGIAN_MODERN 0x1 +#define __drv_typeCond 1 +#define VS_VERSION_INFO 1 +#define VFFF_ISSHAREDFILE 0x0001 +#define VFF_CURNEDEST 0x0001 +#define VIFF_FORCEINSTALL 0x0001 +#define WINAPI_PARTITION_APP 0x00000002 +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 +#define SW_SHOWMINIMIZED 2 +#define SHOW_ICONWINDOW 2 +#define SW_OTHERZOOM 2 +#define VK_RBUTTON 0x02 +#define WM_DESTROY 0x0002 +#define WA_CLICKACTIVE 2 +#define PWR_SUSPENDRESUME 2 +#define NFR_UNICODE 2 +#define UIS_CLEAR 2 +#define UISF_HIDEACCEL 0x2 +#define XBUTTON2 0x0002 +#define WMSZ_RIGHT 2 +#define HTCAPTION 2 +#define SMTO_ABORTIFHUNG 0x0002 +#define MA_ACTIVATEANDEAT 2 +#define ICON_SMALL2 2 +#define SIZE_MAXIMIZED 2 +#define MK_RBUTTON 0x0002 +#define TME_LEAVE 0x00000002 +#define CS_HREDRAW 0x0002 +#define CF_BITMAP 2 +#define IDCANCEL 2 +#define BN_HILITE 2 +#define BST_INDETERMINATE 0x0002 +#define HDS_BUTTONS 0x0002 +#define TBSTYLE_CHECK 0x0002 +#define TTS_NOPREFIX 0x02 +#define TBS_VERT 0x0002 +#define UDS_SETBUDDYINT 0x0002 +#define LWS_IGNORERETURN 0x0002 +#define LVS_SMALLICON 0x0002 +#define TVS_HASLINES 0x0002 +#define TVS_EX_MULTISELECT 0x0002 +#define TCS_BOTTOM 0x0002 +#define TCS_RIGHT 0x0002 +#define ACS_TRANSPARENT 0x0002 +#define MCS_MULTISELECT 0x0002 +#define DTS_SHOWNONE 0x0002 +#define PGS_AUTOSCROLL 0x00000002 +#define NFS_STATIC 0x0002 +#define BCSIF_IMAGE 0x0002 +#define BCSS_STRETCH 0x0002 +#define LANG_BULGARIAN 0x02 +#define SUBLANG_SYS_DEFAULT 0x02 +#define SUBLANG_ARABIC_IRAQ 0x02 +#define SUBLANG_AZERI_CYRILLIC 0x02 +#define SUBLANG_AZERBAIJANI_AZERBAIJAN_CYRILLIC 0x02 +#define SUBLANG_BANGLA_BANGLADESH 0x02 +#define SUBLANG_BENGALI_BANGLADESH 0x02 +#define SUBLANG_CHINESE_SIMPLIFIED 0x02 +#define SUBLANG_DUTCH_BELGIAN 0x02 +#define SUBLANG_ENGLISH_UK 0x02 +#define SUBLANG_FRENCH_BELGIAN 0x02 +#define SUBLANG_FULAH_SENEGAL 0x02 +#define SUBLANG_GERMAN_SWISS 0x02 +#define SUBLANG_INUKTITUT_CANADA_LATIN 0x02 +#define SUBLANG_IRISH_IRELAND 0x02 +#define SUBLANG_ITALIAN_SWISS 0x02 +#define SUBLANG_KASHMIRI_SASIA 0x02 +#define SUBLANG_KASHMIRI_INDIA 0x02 +#define SUBLANG_LOWER_SORBIAN_GERMANY 0x02 +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 +#define SUBLANG_MONGOLIAN_PRC 0x02 +#define SUBLANG_NEPALI_INDIA 0x02 +#define SUBLANG_NORWEGIAN_NYNORSK 0x02 +#define SUBLANG_PORTUGUESE 0x02 +#define SUBLANG_PULAR_SENEGAL 0x02 +#define SUBLANG_PUNJABI_PAKISTAN 0x02 +#define SUBLANG_QUECHUA_ECUADOR 0x02 +#define SUBLANG_SAMI_NORTHERN_SWEDEN 0x02 +#define SUBLANG_SERBIAN_LATIN 0x02 +#define SUBLANG_SINDHI_PAKISTAN 0x02 +#define SUBLANG_SINDHI_AFGHANISTAN 0x02 +#define SUBLANG_SPANISH_MEXICAN 0x02 +#define SUBLANG_SWEDISH_FINLAND 0x02 +#define SUBLANG_TAMAZIGHT_ALGERIA_LATIN 0x02 +#define SUBLANG_TAMIL_SRI_LANKA 0x02 +#define SUBLANG_TIGRIGNA_ERITREA 0x02 +#define SUBLANG_TIGRINYA_ERITREA 0x02 +#define SUBLANG_TSWANA_BOTSWANA 0x02 +#define SUBLANG_URDU_INDIA 0x02 +#define SUBLANG_UZBEK_CYRILLIC 0x02 +#define SUBLANG_VALENCIAN_VALENCIA 0x02 +#define SORT_CHINESE_PRC 0x2 +#define __drv_typeBitset 2 +#define VFF_FILEINUSE 0x0002 +#define VIFF_DONTDELETEOLD 0x0002 +#define VER_PRODUCTMINORVERSION 2 +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 +#define SW_SHOWMAXIMIZED 3 +#define SW_MAXIMIZE 3 +#define SHOW_FULLSCREEN 3 +#define SW_PARENTOPENING 3 +#define VK_CANCEL 0x03 +#define WM_MOVE 0x0003 +#define PWR_CRITICALRESUME 3 +#define NF_QUERY 3 +#define UIS_INITIALIZE 3 +#define WMSZ_TOP 3 +#define HTSYSMENU 3 +#define MA_NOACTIVATE 3 +#define SIZE_MAXSHOW 3 +#define CF_METAFILEPICT 3 +#define IDABORT 3 +#define BN_UNHILITE 3 +#define LVS_LIST 0x0003 +#define LVS_TYPEMASK 0x0003 +#define LANG_CATALAN 0x03 +#define LANG_VALENCIAN 0x03 +#define SUBLANG_CUSTOM_DEFAULT 0x03 +#define SUBLANG_ARABIC_EGYPT 0x03 +#define SUBLANG_CHINESE_HONGKONG 0x03 +#define SUBLANG_ENGLISH_AUS 0x03 +#define SUBLANG_FRENCH_CANADIAN 0x03 +#define SUBLANG_GERMAN_AUSTRIAN 0x03 +#define SUBLANG_QUECHUA_PERU 0x03 +#define SUBLANG_SAMI_NORTHERN_FINLAND 0x03 +#define SUBLANG_SERBIAN_CYRILLIC 0x03 +#define SUBLANG_SPANISH_MODERN 0x03 +#define SORT_CHINESE_BOPOMOFO 0x3 +#define __drv_typeExpr 3 +#define PRODUCT_TAP_WIN_MAJOR 3 +#define SW_SHOWNOACTIVATE 4 +#define SHOW_OPENNOACTIVATE 4 +#define SW_OTHERUNZOOM 4 +#define VK_MBUTTON 0x04 +#define NF_REQUERY 4 +#define UISF_ACTIVE 0x4 +#define WMSZ_TOPLEFT 4 +#define HTGROWBOX 4 +#define MA_NOACTIVATEANDEAT 4 +#define SIZE_MAXHIDE 4 +#define MK_SHIFT 0x0004 +#define CF_SYLK 4 +#define IDRETRY 4 +#define BN_DISABLE 4 +#define BST_PUSHED 0x0004 +#define HDS_HOTTRACK 0x0004 +#define TBSTYLE_GROUP 0x0004 +#define TBS_TOP 0x0004 +#define TBS_LEFT 0x0004 +#define UDS_ALIGNRIGHT 0x0004 +#define PBS_VERTICAL 0x04 +#define LWS_NOPREFIX 0x0004 +#define LVS_SINGLESEL 0x0004 +#define TVS_LINESATROOT 0x0004 +#define TVS_EX_DOUBLEBUFFER 0x0004 +#define TCS_MULTISELECT 0x0004 +#define ACS_AUTOPLAY 0x0004 +#define MCS_WEEKNUMBERS 0x0004 +#define DTS_LONGDATEFORMAT 0x0004 +#define PGS_DRAGNDROP 0x00000004 +#define NFS_LISTCOMBO 0x0004 +#define BCSIF_STYLE 0x0004 +#define BCSS_ALIGNLEFT 0x0004 +#define LANG_CHINESE 0x04 +#define LANG_CHINESE_SIMPLIFIED 0x04 +#define SUBLANG_CUSTOM_UNSPECIFIED 0x04 +#define SUBLANG_ARABIC_LIBYA 0x04 +#define SUBLANG_CHINESE_SINGAPORE 0x04 +#define SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN 0x04 +#define SUBLANG_ENGLISH_CAN 0x04 +#define SUBLANG_FRENCH_SWISS 0x04 +#define SUBLANG_GERMAN_LUXEMBOURG 0x04 +#define SUBLANG_SAMI_LULE_NORWAY 0x04 +#define SUBLANG_SPANISH_GUATEMALA 0x04 +#define SUBLANG_TAMAZIGHT_MOROCCO_TIFINAGH 0x04 +#define SORT_JAPANESE_RADICALSTROKE 0x4 +#define SORT_CHINESE_RADICALSTROKE 0x4 +#define VFF_BUFFTOOSMALL 0x0004 +#define SW_SHOW 5 +#define VK_XBUTTON1 0x05 +#define WM_SIZE 0x0005 +#define WMSZ_TOPRIGHT 5 +#define HTMENU 5 +#define CF_DIF 5 +#define IDIGNORE 5 +#define BN_DOUBLECLICKED 5 +#define LANG_CZECH 0x05 +#define SUBLANG_UI_CUSTOM_DEFAULT 0x05 +#define SUBLANG_ARABIC_ALGERIA 0x05 +#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN 0x05 +#define SUBLANG_CHINESE_MACAU 0x05 +#define SUBLANG_ENGLISH_NZ 0x05 +#define SUBLANG_FRENCH_LUXEMBOURG 0x05 +#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 +#define SUBLANG_SAMI_LULE_SWEDEN 0x05 +#define SUBLANG_SPANISH_COSTA_RICA 0x05 +#define SW_MINIMIZE 6 +#define VK_XBUTTON2 0x06 +#define WM_ACTIVATE 0x0006 +#define WMSZ_BOTTOM 6 +#define HTHSCROLL 6 +#define CF_TIFF 6 +#define IDYES 6 +#define BN_SETFOCUS 6 +#define LANG_DANISH 0x06 +#define SUBLANG_ARABIC_MOROCCO 0x06 +#define SUBLANG_ENGLISH_EIRE 0x06 +#define SUBLANG_FRENCH_MONACO 0x06 +#define SUBLANG_SAMI_SOUTHERN_NORWAY 0x06 +#define SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN 0x06 +#define SUBLANG_SPANISH_PANAMA 0x06 +#define VER_PRODUCTMAJORVERSION 6 +#define SW_SHOWMINNOACTIVE 7 +#define WM_SETFOCUS 0x0007 +#define WMSZ_BOTTOMLEFT 7 +#define HTVSCROLL 7 +#define CF_OEMTEXT 7 +#define IDNO 7 +#define BN_KILLFOCUS 7 +#define LANG_GERMAN 0x07 +#define SUBLANG_ARABIC_TUNISIA 0x07 +#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 +#define SUBLANG_SAMI_SOUTHERN_SWEDEN 0x07 +#define SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x07 +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 +#define SW_SHOWNA 8 +#define VK_BACK 0x08 +#define WM_KILLFOCUS 0x0008 +#define WMSZ_BOTTOMRIGHT 8 +#define HTMINBUTTON 8 +#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 +#define MK_CONTROL 0x0008 +#define CS_DBLCLKS 0x0008 +#define CF_DIB 8 +#define IDCLOSE 8 +#define BST_FOCUS 0x0008 +#define HDS_HIDDEN 0x0008 +#define TBSTYLE_DROPDOWN 0x0008 +#define TBS_BOTH 0x0008 +#define UDS_ALIGNLEFT 0x0008 +#define PBS_MARQUEE 0x08 +#define LWS_USEVISUALSTYLE 0x0008 +#define LVS_SHOWSELALWAYS 0x0008 +#define TVS_EDITLABELS 0x0008 +#define TVS_EX_NOINDENTSTATE 0x0008 +#define TCS_FLATBUTTONS 0x0008 +#define ACS_TIMER 0x0008 +#define MCS_NOTODAYCIRCLE 0x0008 +#define NFS_BUTTON 0x0008 +#define BCSIF_SIZE 0x0008 +#define BCSS_IMAGE 0x0008 +#define LANG_GREEK 0x08 +#define SUBLANG_ARABIC_OMAN 0x08 +#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x08 +#define SUBLANG_ENGLISH_JAMAICA 0x08 +#define SUBLANG_SAMI_SKOLT_FINLAND 0x08 +#define SUBLANG_SPANISH_VENEZUELA 0x08 +#define SW_RESTORE 9 +#define VK_TAB 0x09 +#define HTMAXBUTTON 9 +#define CF_PALETTE 9 +#define IDHELP 9 +#define DTS_TIMEFORMAT 0x0009 +#define LANG_ENGLISH 0x09 +#define SUBLANG_ARABIC_YEMEN 0x09 +#define SUBLANG_ENGLISH_CARIBBEAN 0x09 +#define SUBLANG_SAMI_INARI_FINLAND 0x09 +#define SUBLANG_SERBIAN_SERBIA_LATIN 0x09 +#define SUBLANG_SPANISH_COLOMBIA 0x09 +#define SW_SHOWDEFAULT 10 +#define WM_ENABLE 0x000A +#define HTLEFT 10 +#define CF_PENDATA 10 +#define IDTRYAGAIN 10 +#define HELP_CONTEXTMENU 0x000a +#define LANG_SPANISH 0x0a +#define SUBLANG_ARABIC_SYRIA 0x0a +#define SUBLANG_ENGLISH_BELIZE 0x0a +#define SUBLANG_SERBIAN_SERBIA_CYRILLIC 0x0a +#define SUBLANG_SPANISH_PERU 0x0a +#define SW_FORCEMINIMIZE 11 +#define SW_MAX 11 +#define WM_SETREDRAW 0x000B +#define HTRIGHT 11 +#define CF_RIFF 11 +#define IDCONTINUE 11 +#define HELP_FINDER 0x000b +#define LANG_FINNISH 0x0b +#define SUBLANG_ARABIC_JORDAN 0x0b +#define SUBLANG_ENGLISH_TRINIDAD 0x0b +#define SUBLANG_SERBIAN_MONTENEGRO_LATIN 0x0b +#define SUBLANG_SPANISH_ARGENTINA 0x0b +#define VK_CLEAR 0x0C +#define WM_SETTEXT 0x000C +#define HTTOP 12 +#define CF_WAVE 12 +#define HELP_WM_HELP 0x000c +#define DTS_SHORTDATECENTURYFORMAT 0x000C +#define LANG_FRENCH 0x0c +#define SUBLANG_ARABIC_LEBANON 0x0c +#define SUBLANG_ENGLISH_ZIMBABWE 0x0c +#define SUBLANG_SERBIAN_MONTENEGRO_CYRILLIC 0x0c +#define SUBLANG_SPANISH_ECUADOR 0x0c +#define VK_RETURN 0x0D +#define WM_GETTEXT 0x000D +#define HTTOPLEFT 13 +#define CF_UNICODETEXT 13 +#define HELP_SETPOPUP_POS 0x000d +#define LANG_HEBREW 0x0d +#define SUBLANG_ARABIC_KUWAIT 0x0d +#define SUBLANG_ENGLISH_PHILIPPINES 0x0d +#define SUBLANG_SPANISH_CHILE 0x0d +#define WM_GETTEXTLENGTH 0x000E +#define HTTOPRIGHT 14 +#define CF_ENHMETAFILE 14 +#define LANG_HUNGARIAN 0x0e +#define SUBLANG_ARABIC_UAE 0x0e +#define SUBLANG_SPANISH_URUGUAY 0x0e +#define WM_PAINT 0x000F +#define HTBOTTOM 15 +#define CF_HDROP 15 +#define LANG_ICELANDIC 0x0f +#define SUBLANG_ARABIC_BAHRAIN 0x0f +#define SUBLANG_SPANISH_PARAGUAY 0x0f +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 +#define VK_SHIFT 0x10 +#define WM_CLOSE 0x0010 +#define HTBOTTOMLEFT 16 +#define WVR_ALIGNTOP 0x0010 +#define MK_MBUTTON 0x0010 +#define TME_NONCLIENT 0x00000010 +#define CF_LOCALE 16 +#define HELP_TCARD_DATA 0x0010 +#define TBSTYLE_AUTOSIZE 0x0010 +#define TTS_NOANIMATE 0x10 +#define TBS_NOTICKS 0x0010 +#define UDS_AUTOBUDDY 0x0010 +#define PBS_SMOOTHREVERSE 0x10 +#define LWS_USECUSTOMTEXT 0x0010 +#define LVS_SORTASCENDING 0x0010 +#define TVS_DISABLEDRAGDROP 0x0010 +#define TVS_EX_RICHTOOLTIP 0x0010 +#define TCS_FORCEICONLEFT 0x0010 +#define MCS_NOTODAY 0x0010 +#define DTS_APPCANPARSE 0x0010 +#define NFS_ALL 0x0010 +#define LANG_ITALIAN 0x10 +#define SUBLANG_ARABIC_QATAR 0x10 +#define SUBLANG_ENGLISH_INDIA 0x10 +#define SUBLANG_SPANISH_BOLIVIA 0x10 +#define VK_CONTROL 0x11 +#define WM_QUERYENDSESSION 0x0011 +#define HTBOTTOMRIGHT 17 +#define CF_DIBV5 17 +#define HELP_TCARD_OTHER_CALLER 0x0011 +#define LANG_JAPANESE 0x11 +#define SUBLANG_ENGLISH_MALAYSIA 0x11 +#define SUBLANG_SPANISH_EL_SALVADOR 0x11 +#define VK_MENU 0x12 +#define WM_QUIT 0x0012 +#define HTBORDER 18 +#define CF_MAX 18 +#define LANG_KOREAN 0x12 +#define SUBLANG_ENGLISH_SINGAPORE 0x12 +#define SUBLANG_SPANISH_HONDURAS 0x12 +#define VK_PAUSE 0x13 +#define WM_QUERYOPEN 0x0013 +#define HTOBJECT 19 +#define LANG_DUTCH 0x13 +#define SUBLANG_SPANISH_NICARAGUA 0x13 +#define VK_CAPITAL 0x14 +#define WM_ERASEBKGND 0x0014 +#define HTCLOSE 20 +#define LANG_NORWEGIAN 0x14 +#define SUBLANG_SPANISH_PUERTO_RICO 0x14 +#define _SAL_VERSION 20 +#define VK_KANA 0x15 +#define VK_HANGEUL 0x15 +#define VK_HANGUL 0x15 +#define WM_SYSCOLORCHANGE 0x0015 +#define HTHELP 21 +#define LANG_POLISH 0x15 +#define SUBLANG_SPANISH_US 0x15 +#define WM_ENDSESSION 0x0016 +#define LANG_PORTUGUESE 0x16 +#define VK_JUNJA 0x17 +#define LANG_ROMANSH 0x17 +#define RT_MANIFEST 24 +#define VK_FINAL 0x18 +#define WM_SHOWWINDOW 0x0018 +#define LANG_ROMANIAN 0x18 +#define VK_HANJA 0x19 +#define VK_KANJI 0x19 +#define LANG_RUSSIAN 0x19 +#define WM_WININICHANGE 0x001A +#define LANG_BOSNIAN 0x1a +#define LANG_CROATIAN 0x1a +#define LANG_SERBIAN 0x1a +#define VK_ESCAPE 0x1B +#define WM_DEVMODECHANGE 0x001B +#define LANG_SLOVAK 0x1b +#define VK_CONVERT 0x1C +#define WM_ACTIVATEAPP 0x001C +#define LANG_ALBANIAN 0x1c +#define VK_NONCONVERT 0x1D +#define WM_FONTCHANGE 0x001D +#define LANG_SWEDISH 0x1d +#define VK_ACCEPT 0x1E +#define WM_TIMECHANGE 0x001E +#define LANG_THAI 0x1e +#define VK_MODECHANGE 0x1F +#define WM_CANCELMODE 0x001F +#define LANG_TURKISH 0x1f +#define VK_SPACE 0x20 +#define WM_SETCURSOR 0x0020 +#define SMTO_ERRORONEXIT 0x0020 +#define WVR_ALIGNLEFT 0x0020 +#define MK_XBUTTON1 0x0020 +#define CS_OWNDC 0x0020 +#define TBSTYLE_NOPREFIX 0x0020 +#define TTS_NOFADE 0x20 +#define TBS_ENABLESELRANGE 0x0020 +#define UDS_ARROWKEYS 0x0020 +#define LWS_RIGHT 0x0020 +#define LVS_SORTDESCENDING 0x0020 +#define TVS_SHOWSELALWAYS 0x0020 +#define TVS_EX_AUTOHSCROLL 0x0020 +#define TCS_FORCELABELLEFT 0x0020 +#define DTS_RIGHTALIGN 0x0020 +#define NFS_USEFONTASSOC 0x0020 +#define LANG_URDU 0x20 +#define VK_PRIOR 0x21 +#define WM_MOUSEACTIVATE 0x0021 +#define LANG_INDONESIAN 0x21 +#define VK_NEXT 0x22 +#define WM_CHILDACTIVATE 0x0022 +#define LANG_UKRAINIAN 0x22 +#define VK_END 0x23 +#define WM_QUEUESYNC 0x0023 +#define LANG_BELARUSIAN 0x23 +#define VK_HOME 0x24 +#define WM_GETMINMAXINFO 0x0024 +#define LANG_SLOVENIAN 0x24 +#define VK_LEFT 0x25 +#define LANG_ESTONIAN 0x25 +#define VK_UP 0x26 +#define WM_PAINTICON 0x0026 +#define LANG_LATVIAN 0x26 +#define VK_RIGHT 0x27 +#define WM_ICONERASEBKGND 0x0027 +#define LANG_LITHUANIAN 0x27 +#define VK_DOWN 0x28 +#define WM_NEXTDLGCTL 0x0028 +#define LANG_TAJIK 0x28 +#define VK_SELECT 0x29 +#define LANG_FARSI 0x29 +#define LANG_PERSIAN 0x29 +#define VK_PRINT 0x2A +#define WM_SPOOLERSTATUS 0x002A +#define LANG_VIETNAMESE 0x2a +#define VK_EXECUTE 0x2B +#define WM_DRAWITEM 0x002B +#define LANG_ARMENIAN 0x2b +#define VK_SNAPSHOT 0x2C +#define WM_MEASUREITEM 0x002C +#define LANG_AZERI 0x2c +#define LANG_AZERBAIJANI 0x2c +#define VK_INSERT 0x2D +#define WM_DELETEITEM 0x002D +#define LANG_BASQUE 0x2d +#define VK_DELETE 0x2E +#define WM_VKEYTOITEM 0x002E +#define LANG_LOWER_SORBIAN 0x2e +#define LANG_UPPER_SORBIAN 0x2e +#define VK_HELP 0x2F +#define WM_CHARTOITEM 0x002F +#define LANG_MACEDONIAN 0x2f +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_SETHOTKEY 0x0032 +#define LANG_TSWANA 0x32 +#define WM_GETHOTKEY 0x0033 +#define LANG_XHOSA 0x34 +#define LANG_ZULU 0x35 +#define LANG_AFRIKAANS 0x36 +#define WM_QUERYDRAGICON 0x0037 +#define LANG_GEORGIAN 0x37 +#define LANG_FAEROESE 0x38 +#define WM_COMPAREITEM 0x0039 +#define LANG_HINDI 0x39 +#define LANG_MALTESE 0x3a +#define LANG_SAMI 0x3b +#define LANG_IRISH 0x3c +#define WM_GETOBJECT 0x003D +#define LANG_MALAY 0x3e +#define LANG_KAZAK 0x3f +#define WVR_ALIGNBOTTOM 0x0040 +#define MK_XBUTTON2 0x0040 +#define CS_CLASSDC 0x0040 +#define HDS_DRAGDROP 0x0040 +#define BTNS_SHOWTEXT 0x0040 +#define TTS_BALLOON 0x40 +#define TBS_FIXEDLENGTH 0x0040 +#define UDS_HORZ 0x0040 +#define LVS_SHAREIMAGELISTS 0x0040 +#define TVS_RTLREADING 0x0040 +#define TVS_EX_FADEINOUTEXPANDOS 0x0040 +#define TCS_HOTTRACK 0x0040 +#define MCS_NOTRAILINGDATES 0x0040 +#define LANG_KYRGYZ 0x40 +#define WM_COMPACTING 0x0041 +#define LANG_SWAHILI 0x41 +#define LANG_TURKMEN 0x42 +#define LANG_UZBEK 0x43 +#define WM_COMMNOTIFY 0x0044 +#define LANG_TATAR 0x44 +#define LANG_BANGLA 0x45 +#define LANG_BENGALI 0x45 +#define WM_WINDOWPOSCHANGING 0x0046 +#define LANG_PUNJABI 0x46 +#define WM_WINDOWPOSCHANGED 0x0047 +#define LANG_GUJARATI 0x47 +#define WM_POWER 0x0048 +#define LANG_ODIA 0x48 +#define LANG_ORIYA 0x48 +#define LANG_TAMIL 0x49 +#define WM_COPYDATA 0x004A +#define LANG_TELUGU 0x4a +#define WM_CANCELJOURNAL 0x004B +#define LANG_KANNADA 0x4b +#define LANG_MALAYALAM 0x4c +#define LANG_ASSAMESE 0x4d +#define WM_NOTIFY 0x004E +#define LANG_MARATHI 0x4e +#define LANG_SANSKRIT 0x4f +#define WM_INPUTLANGCHANGEREQUEST 0x0050 +#define LANG_MONGOLIAN 0x50 +#define WM_INPUTLANGCHANGE 0x0051 +#define LANG_TIBETAN 0x51 +#define WM_TCARD 0x0052 +#define LANG_WELSH 0x52 +#define WM_HELP 0x0053 +#define LANG_KHMER 0x53 +#define WM_USERCHANGED 0x0054 +#define LANG_LAO 0x54 +#define WM_NOTIFYFORMAT 0x0055 +#define LANG_GALICIAN 0x56 +#define LANG_KONKANI 0x57 +#define LANG_MANIPURI 0x58 +#define LANG_SINDHI 0x59 +#define LANG_SYRIAC 0x5a +#define VK_LWIN 0x5B +#define LANG_SINHALESE 0x5b +#define VK_RWIN 0x5C +#define LANG_CHEROKEE 0x5c +#define VK_APPS 0x5D +#define LANG_INUKTITUT 0x5d +#define LANG_AMHARIC 0x5e +#define VK_SLEEP 0x5F +#define LANG_TAMAZIGHT 0x5f +#define VK_NUMPAD0 0x60 +#define LANG_KASHMIRI 0x60 +#define VK_NUMPAD1 0x61 +#define LANG_NEPALI 0x61 +#define VK_NUMPAD2 0x62 +#define LANG_FRISIAN 0x62 +#define VK_NUMPAD3 0x63 +#define LANG_PASHTO 0x63 +#define VK_NUMPAD4 0x64 +#define LANG_FILIPINO 0x64 +#define VS_USER_DEFINED 100 +#define VK_NUMPAD5 0x65 +#define LANG_DIVEHI 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define LANG_FULAH 0x67 +#define LANG_PULAR 0x67 +#define VK_NUMPAD8 0x68 +#define LANG_HAUSA 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define LANG_YORUBA 0x6a +#define VK_ADD 0x6B +#define LANG_QUECHUA 0x6b +#define VK_SEPARATOR 0x6C +#define LANG_SOTHO 0x6c +#define VK_SUBTRACT 0x6D +#define LANG_BASHKIR 0x6d +#define VK_DECIMAL 0x6E +#define LANG_LUXEMBOURGISH 0x6e +#define VK_DIVIDE 0x6F +#define LANG_GREENLANDIC 0x6f +#define VK_F1 0x70 +#define LANG_IGBO 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define LANG_TIGRIGNA 0x73 +#define LANG_TIGRINYA 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define LANG_HAWAIIAN 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define WHEEL_DELTA 120 +#define LANG_YI 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define LANG_MAPUDUNGUN 0x7a +#define VK_F12 0x7B +#define WM_CONTEXTMENU 0x007B +#define VK_F13 0x7C +#define WM_STYLECHANGING 0x007C +#define LANG_MOHAWK 0x7c +#define VK_F14 0x7D +#define WM_STYLECHANGED 0x007D +#define VK_F15 0x7E +#define WM_DISPLAYCHANGE 0x007E +#define LANG_BRETON 0x7e +#define VK_F16 0x7F +#define WM_GETICON 0x007F +#define LANG_INVARIANT 0x7f +#define VK_F17 0x80 +#define WM_SETICON 0x0080 +#define WVR_ALIGNRIGHT 0x0080 +#define CS_PARENTDC 0x0080 +#define CF_OWNERDISPLAY 0x0080 +#define HDS_FULLDRAG 0x0080 +#define BTNS_WHOLEDROPDOWN 0x0080 +#define TTS_CLOSE 0x80 +#define TBS_NOTHUMB 0x0080 +#define UDS_NOTHOUSANDS 0x0080 +#define LVS_NOLABELWRAP 0x0080 +#define TVS_NOTOOLTIPS 0x0080 +#define TVS_EX_PARTIALCHECKBOXES 0x0080 +#define TCS_VERTICAL 0x0080 +#define MCS_SHORTDAYSOFWEEK 0x0080 +#define LANG_UIGHUR 0x80 +#define VK_F18 0x81 +#define WM_NCCREATE 0x0081 +#define CF_DSPTEXT 0x0081 +#define LANG_MAORI 0x81 +#define VK_F19 0x82 +#define WM_NCDESTROY 0x0082 +#define CF_DSPBITMAP 0x0082 +#define LANG_OCCITAN 0x82 +#define VK_F20 0x83 +#define WM_NCCALCSIZE 0x0083 +#define CF_DSPMETAFILEPICT 0x0083 +#define LANG_CORSICAN 0x83 +#define VK_F21 0x84 +#define WM_NCHITTEST 0x0084 +#define LANG_ALSATIAN 0x84 +#define VK_F22 0x85 +#define WM_NCPAINT 0x0085 +#define LANG_SAKHA 0x85 +#define LANG_YAKUT 0x85 +#define VK_F23 0x86 +#define WM_NCACTIVATE 0x0086 +#define LANG_KICHE 0x86 +#define VK_F24 0x87 +#define WM_GETDLGCODE 0x0087 +#define LANG_KINYARWANDA 0x87 +#define WM_SYNCPAINT 0x0088 +#define LANG_WOLOF 0x88 +#define LANG_DARI 0x8c +#define CF_DSPENHMETAFILE 0x008E +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +#define LANG_SCOTTISH_GAELIC 0x91 +#define VK_OEM_NEC_EQUAL 0x92 +#define VK_OEM_FJ_JISHO 0x92 +#define LANG_CENTRAL_KURDISH 0x92 +#define VK_OEM_FJ_MASSHOU 0x93 +#define VK_OEM_FJ_TOUROKU 0x94 +#define VK_OEM_FJ_LOYA 0x95 +#define VK_OEM_FJ_ROYA 0x96 +#define VK_LSHIFT 0xA0 +#define WM_NCMOUSEMOVE 0x00A0 +#define VK_RSHIFT 0xA1 +#define WM_NCLBUTTONDOWN 0x00A1 +#define VK_LCONTROL 0xA2 +#define WM_NCLBUTTONUP 0x00A2 +#define VK_RCONTROL 0xA3 +#define WM_NCLBUTTONDBLCLK 0x00A3 +#define VK_LMENU 0xA4 +#define WM_NCRBUTTONDOWN 0x00A4 +#define VK_RMENU 0xA5 +#define WM_NCRBUTTONUP 0x00A5 +#define VK_BROWSER_BACK 0xA6 +#define WM_NCRBUTTONDBLCLK 0x00A6 +#define VK_BROWSER_FORWARD 0xA7 +#define WM_NCMBUTTONDOWN 0x00A7 +#define VK_BROWSER_REFRESH 0xA8 +#define WM_NCMBUTTONUP 0x00A8 +#define VK_BROWSER_STOP 0xA9 +#define WM_NCMBUTTONDBLCLK 0x00A9 +#define VK_BROWSER_SEARCH 0xAA +#define VK_BROWSER_FAVORITES 0xAB +#define WM_NCXBUTTONDOWN 0x00AB +#define VK_BROWSER_HOME 0xAC +#define WM_NCXBUTTONUP 0x00AC +#define VK_VOLUME_MUTE 0xAD +#define WM_NCXBUTTONDBLCLK 0x00AD +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define EM_GETSEL 0x00B0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define EM_SETSEL 0x00B1 +#define VK_MEDIA_STOP 0xB2 +#define EM_GETRECT 0x00B2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#define EM_SETRECT 0x00B3 +#define VK_LAUNCH_MAIL 0xB4 +#define EM_SETRECTNP 0x00B4 +#define VK_LAUNCH_MEDIA_SELECT 0xB5 +#define EM_SCROLL 0x00B5 +#define VK_LAUNCH_APP1 0xB6 +#define EM_LINESCROLL 0x00B6 +#define VK_LAUNCH_APP2 0xB7 +#define EM_SCROLLCARET 0x00B7 +#define EM_GETMODIFY 0x00B8 +#define EM_SETMODIFY 0x00B9 +#define VK_OEM_1 0xBA +#define EM_GETLINECOUNT 0x00BA +#define VK_OEM_PLUS 0xBB +#define EM_LINEINDEX 0x00BB +#define VK_OEM_COMMA 0xBC +#define EM_SETHANDLE 0x00BC +#define VK_OEM_MINUS 0xBD +#define EM_GETHANDLE 0x00BD +#define VK_OEM_PERIOD 0xBE +#define EM_GETTHUMB 0x00BE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +#define EM_LINELENGTH 0x00C1 +#define EM_REPLACESEL 0x00C2 +#define EM_GETLINE 0x00C4 +#define EM_LIMITTEXT 0x00C5 +#define EM_CANUNDO 0x00C6 +#define EM_UNDO 0x00C7 +#define EM_FMTLINES 0x00C8 +#define EM_LINEFROMCHAR 0x00C9 +#define EM_SETTABSTOPS 0x00CB +#define EM_SETPASSWORDCHAR 0x00CC +#define EM_EMPTYUNDOBUFFER 0x00CD +#define EM_GETFIRSTVISIBLELINE 0x00CE +#define EM_SETREADONLY 0x00CF +#define EM_SETWORDBREAKPROC 0x00D0 +#define EM_GETWORDBREAKPROC 0x00D1 +#define EM_GETPASSWORDCHAR 0x00D2 +#define EM_SETMARGINS 0x00D3 +#define EM_GETMARGINS 0x00D4 +#define EM_GETLIMITTEXT 0x00D5 +#define EM_POSFROMCHAR 0x00D6 +#define EM_CHARFROMPOS 0x00D7 +#define EM_SETIMESTATUS 0x00D8 +#define EM_GETIMESTATUS 0x00D9 +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +#define VK_OEM_8 0xDF +#define VK_OEM_AX 0xE1 +#define VK_OEM_102 0xE2 +#define VK_ICO_HELP 0xE3 +#define VK_ICO_00 0xE4 +#define VK_PROCESSKEY 0xE5 +#define VK_ICO_CLEAR 0xE6 +#define VK_PACKET 0xE7 +#define VK_OEM_RESET 0xE9 +#define VK_OEM_JUMP 0xEA +#define VK_OEM_PA1 0xEB +#define VK_OEM_PA2 0xEC +#define VK_OEM_PA3 0xED +#define VK_OEM_WSCTRL 0xEE +#define VK_OEM_CUSEL 0xEF +#define VK_OEM_ATTN 0xF0 +#define BM_GETCHECK 0x00F0 +#define VK_OEM_FINISH 0xF1 +#define BM_SETCHECK 0x00F1 +#define VK_OEM_COPY 0xF2 +#define BM_GETSTATE 0x00F2 +#define VK_OEM_AUTO 0xF3 +#define BM_SETSTATE 0x00F3 +#define VK_OEM_ENLW 0xF4 +#define BM_SETSTYLE 0x00F4 +#define VK_OEM_BACKTAB 0xF5 +#define BM_CLICK 0x00F5 +#define VK_ATTN 0xF6 +#define BM_GETIMAGE 0x00F6 +#define VK_CRSEL 0xF7 +#define BM_SETIMAGE 0x00F7 +#define VK_EXSEL 0xF8 +#define BM_SETDONTCLICK 0x00F8 +#define VK_EREOF 0xF9 +#define VK_PLAY 0xFA +#define VK_ZOOM 0xFB +#define VK_NONAME 0xFC +#define VK_PA1 0xFD +#define VK_OEM_CLEAR 0xFE +#define WM_INPUT_DEVICE_CHANGE 0x00FE +#define SUBVERSION_MASK 0x000000FF +#define WM_INPUT 0x00FF +#define WM_KEYFIRST 0x0100 +#define WM_KEYDOWN 0x0100 +#define WVR_HREDRAW 0x0100 +#define HDS_FILTERBAR 0x0100 +#define TBSTYLE_TOOLTIPS 0x0100 +#define RBS_TOOLTIPS 0x00000100 +#define TTS_USEVISUALSTYLE 0x100 +#define SBARS_SIZEGRIP 0x0100 +#define TBS_TOOLTIPS 0x0100 +#define UDS_HOTTRACK 0x0100 +#define LVS_AUTOARRANGE 0x0100 +#define TVS_CHECKBOXES 0x0100 +#define TVS_EX_EXCLUSIONCHECKBOXES 0x0100 +#define TCS_BUTTONS 0x0100 +#define MCS_NOSELCHANGEONNAV 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_UNICHAR 0x0109 +#define WM_KEYLAST 0x0109 +#define WM_IME_STARTCOMPOSITION 0x010D +#define WM_IME_ENDCOMPOSITION 0x010E +#define WM_IME_COMPOSITION 0x010F +#define WM_IME_KEYLAST 0x010F +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 +#define WM_GESTURE 0x0119 +#define WM_GESTURENOTIFY 0x011A +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 +#define WM_MENURBUTTONUP 0x0122 +#define WM_MENUDRAG 0x0123 +#define WM_MENUGETOBJECT 0x0124 +#define WM_UNINITMENUPOPUP 0x0125 +#define WM_MENUCOMMAND 0x0126 +#define WM_CHANGEUISTATE 0x0127 +#define WM_UPDATEUISTATE 0x0128 +#define WM_QUERYUISTATE 0x0129 +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 +#define MN_GETHMENU 0x01E1 +#define _WIN32_IE_IE20 0x0200 +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSEMOVE 0x0200 +#define WVR_VREDRAW 0x0200 +#define CS_NOCLOSE 0x0200 +#define CF_PRIVATEFIRST 0x0200 +#define HDS_FLAT 0x0200 +#define TBSTYLE_WRAPABLE 0x0200 +#define RBS_VARHEIGHT 0x00000200 +#define TBS_REVERSED 0x0200 +#define LVS_EDITLABELS 0x0200 +#define TVS_TRACKSELECT 0x0200 +#define TVS_EX_DIMMEDCHECKBOXES 0x0200 +#define TCS_MULTILINE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_MOUSEHWHEEL 0x020E +#define WM_MOUSELAST 0x020E +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 +#define WM_NEXTMENU 0x0213 +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 +#define WM_POWERBROADCAST 0x0218 +#define WM_DEVICECHANGE 0x0219 +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 +#define WM_MDISETMENU 0x0230 +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 +#define WM_MDIREFRESHMENU 0x0234 +#define WM_POINTERDEVICECHANGE 0x238 +#define WM_POINTERDEVICEINRANGE 0x239 +#define WM_POINTERDEVICEOUTOFRANGE 0x23A +#define WM_TOUCH 0x0240 +#define WM_NCPOINTERUPDATE 0x0241 +#define WM_NCPOINTERDOWN 0x0242 +#define WM_NCPOINTERUP 0x0243 +#define WM_POINTERUPDATE 0x0245 +#define WM_POINTERDOWN 0x0246 +#define WM_POINTERUP 0x0247 +#define WM_POINTERENTER 0x0249 +#define WM_POINTERLEAVE 0x024A +#define WM_POINTERACTIVATE 0x024B +#define WM_POINTERCAPTURECHANGED 0x024C +#define WM_TOUCHHITTESTING 0x024D +#define WM_POINTERWHEEL 0x024E +#define WM_POINTERHWHEEL 0x024F +#define WM_IME_SETCONTEXT 0x0281 +#define WM_IME_NOTIFY 0x0282 +#define WM_IME_CONTROL 0x0283 +#define WM_IME_COMPOSITIONFULL 0x0284 +#define WM_IME_SELECT 0x0285 +#define WM_IME_CHAR 0x0286 +#define WM_IME_REQUEST 0x0288 +#define WM_IME_KEYDOWN 0x0290 +#define WM_IME_KEYUP 0x0291 +#define WM_NCMOUSEHOVER 0x02A0 +#define WM_MOUSEHOVER 0x02A1 +#define WM_NCMOUSELEAVE 0x02A2 +#define WM_MOUSELEAVE 0x02A3 +#define WM_WTSSESSION_CHANGE 0x02B1 +#define WM_TABLET_FIRST 0x02c0 +#define WM_TABLET_LAST 0x02df +#define CF_PRIVATELAST 0x02FF +#define _WIN32_IE_IE30 0x0300 +#define WM_CUT 0x0300 +#define CF_GDIOBJFIRST 0x0300 +#define WM_COPY 0x0301 +#define _WIN32_IE_IE302 0x0302 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 +#define WM_RENDERFORMAT 0x0305 +#define WM_RENDERALLFORMATS 0x0306 +#define WM_DESTROYCLIPBOARD 0x0307 +#define WM_DRAWCLIPBOARD 0x0308 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_VSCROLLCLIPBOARD 0x030A +#define WM_SIZECLIPBOARD 0x030B +#define WM_ASKCBFORMATNAME 0x030C +#define WM_CHANGECBCHAIN 0x030D +#define WM_HSCROLLCLIPBOARD 0x030E +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTEISCHANGING 0x0310 +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 +#define WM_APPCOMMAND 0x0319 +#define WM_THEMECHANGED 0x031A +#define WM_CLIPBOARDUPDATE 0x031D +#define WM_DWMCOMPOSITIONCHANGED 0x031E +#define WM_DWMNCRENDERINGCHANGED 0x031F +#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 +#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321 +#define WM_DWMSENDICONICTHUMBNAIL 0x0323 +#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326 +#define WM_GETTITLEBARINFOEX 0x033F +#define WM_HANDHELDFIRST 0x0358 +#define WM_HANDHELDLAST 0x035F +#define WM_AFXFIRST 0x0360 +#define WM_AFXLAST 0x037F +#define WM_PENWINFIRST 0x0380 +#define WM_PENWINLAST 0x038F +#define WM_DDE_FIRST 0x03E0 +#define CF_GDIOBJLAST 0x03FF +#define _WIN32_WINNT_NT4 0x0400 +#define _WIN32_IE_IE40 0x0400 +#define WM_USER 0x0400 +#define WVR_VALIDRECTS 0x0400 +#define HDS_CHECKBOXES 0x0400 +#define TBSTYLE_ALTDRAG 0x0400 +#define RBS_BANDBORDERS 0x00000400 +#define TBS_DOWNISLEFT 0x0400 +#define LVS_OWNERDRAWFIXED 0x0400 +#define TVS_SINGLEEXPAND 0x0400 +#define TVS_EX_DRAWIMAGEASYNC 0x0400 +#define TCS_FIXEDWIDTH 0x0400 +#define ctlFirst 0x0400 +#define psh1 0x0400 +#define _WIN32_IE_IE401 0x0401 +#define psh2 0x0401 +#define psh3 0x0402 +#define psh4 0x0403 +#define psh5 0x0404 +#define psh6 0x0405 +#define psh7 0x0406 +#define psh8 0x0407 +#define psh9 0x0408 +#define psh10 0x0409 +#define psh11 0x040a +#define psh12 0x040b +#define psh13 0x040c +#define psh14 0x040d +#define psh15 0x040e +#define psh16 0x040f +#define _WIN32_WINDOWS 0x0410 +#define chx1 0x0410 +#define chx2 0x0411 +#define chx3 0x0412 +#define chx4 0x0413 +#define chx5 0x0414 +#define chx6 0x0415 +#define chx7 0x0416 +#define chx8 0x0417 +#define chx9 0x0418 +#define chx10 0x0419 +#define chx11 0x041a +#define chx12 0x041b +#define chx13 0x041c +#define chx14 0x041d +#define chx15 0x041e +#define chx16 0x041f +#define rad1 0x0420 +#define rad2 0x0421 +#define rad3 0x0422 +#define rad4 0x0423 +#define rad5 0x0424 +#define rad6 0x0425 +#define rad7 0x0426 +#define rad8 0x0427 +#define rad9 0x0428 +#define rad10 0x0429 +#define rad11 0x042a +#define rad12 0x042b +#define rad13 0x042c +#define rad14 0x042d +#define rad15 0x042e +#define rad16 0x042f +#define grp1 0x0430 +#define grp2 0x0431 +#define grp3 0x0432 +#define grp4 0x0433 +#define frm1 0x0434 +#define frm2 0x0435 +#define frm3 0x0436 +#define frm4 0x0437 +#define rct1 0x0438 +#define rct2 0x0439 +#define rct3 0x043a +#define rct4 0x043b +#define ico1 0x043c +#define ico2 0x043d +#define ico3 0x043e +#define ico4 0x043f +#define stc1 0x0440 +#define stc2 0x0441 +#define stc3 0x0442 +#define stc4 0x0443 +#define stc5 0x0444 +#define stc6 0x0445 +#define stc7 0x0446 +#define stc8 0x0447 +#define stc9 0x0448 +#define stc10 0x0449 +#define stc11 0x044a +#define stc12 0x044b +#define stc13 0x044c +#define stc14 0x044d +#define stc15 0x044e +#define stc16 0x044f +#define stc17 0x0450 +#define stc18 0x0451 +#define stc19 0x0452 +#define stc20 0x0453 +#define stc21 0x0454 +#define stc22 0x0455 +#define stc23 0x0456 +#define stc24 0x0457 +#define stc25 0x0458 +#define stc26 0x0459 +#define stc27 0x045a +#define stc28 0x045b +#define stc29 0x045c +#define stc30 0x045d +#define stc31 0x045e +#define stc32 0x045f +#define lst1 0x0460 +#define lst2 0x0461 +#define lst3 0x0462 +#define lst4 0x0463 +#define lst5 0x0464 +#define lst6 0x0465 +#define lst7 0x0466 +#define lst8 0x0467 +#define lst9 0x0468 +#define lst10 0x0469 +#define lst11 0x046a +#define lst12 0x046b +#define lst13 0x046c +#define lst14 0x046d +#define lst15 0x046e +#define lst16 0x046f +#define cmb1 0x0470 +#define cmb2 0x0471 +#define cmb3 0x0472 +#define cmb4 0x0473 +#define cmb5 0x0474 +#define cmb6 0x0475 +#define cmb7 0x0476 +#define cmb8 0x0477 +#define cmb9 0x0478 +#define cmb10 0x0479 +#define cmb11 0x047a +#define cmb12 0x047b +#define cmb13 0x047c +#define cmb14 0x047d +#define cmb15 0x047e +#define cmb16 0x047f +#define edt1 0x0480 +#define edt2 0x0481 +#define edt3 0x0482 +#define edt4 0x0483 +#define edt5 0x0484 +#define edt6 0x0485 +#define edt7 0x0486 +#define edt8 0x0487 +#define edt9 0x0488 +#define edt10 0x0489 +#define edt11 0x048a +#define edt12 0x048b +#define edt13 0x048c +#define edt14 0x048d +#define edt15 0x048e +#define edt16 0x048f +#define scr1 0x0490 +#define scr2 0x0491 +#define scr3 0x0492 +#define scr4 0x0493 +#define scr5 0x0494 +#define scr6 0x0495 +#define scr7 0x0496 +#define scr8 0x0497 +#define ctl1 0x04A0 +#define ctlLast 0x04ff +#define _WIN32_WINNT_WIN2K 0x0500 +#define _WIN32_IE_IE50 0x0500 +#define _WIN32_WINNT_WINXP 0x0501 +#define _WIN32_IE_IE501 0x0501 +#define _WIN32_WINNT_WS03 0x0502 +#define _WIN32_IE_IE55 0x0550 +#define _WIN32_WINNT_WIN6 0x0600 +#define _WIN32_WINNT_VISTA 0x0600 +#define _WIN32_WINNT_WS08 0x0600 +#define _WIN32_WINNT_LONGHORN 0x0600 +#define _WIN32_IE_IE60 0x0600 +#define FILEOPENORD 1536 +#define _WIN32_WINNT_WIN7 0x0601 +#define _WIN32_IE_IE60SP1 0x0601 +#define MULTIFILEOPENORD 1537 +#define _WIN32_WINNT_WIN8 0x0602 +#define _WIN32_IE_WS03 0x0602 +#define _WIN32_WINNT 0x0602 +#define PRINTDLGORD 1538 +#define VER_PRODUCTVERSION_W 0x0602 +#define _WIN32_IE_IE60SP2 0x0603 +#define PRNSETUPDLGORD 1539 +#define FINDDLGORD 1540 +#define REPLACEDLGORD 1541 +#define FONTDLGORD 1542 +#define FORMATDLGORD31 1543 +#define FORMATDLGORD30 1544 +#define RUNDLGORD 1545 +#define PAGESETUPDLGORD 1546 +#define NEWFILEOPENORD 1547 +#define PRINTDLGEXORD 1549 +#define PAGESETUPDLGORDMOTIF 1550 +#define COLORMGMTDLGORD 1551 +#define NEWFILEOPENV2ORD 1552 +#define NEWFILEOPENV3ORD 1553 +#define NEWFORMATDLGWITHLINK 1591 +#define IDC_MANAGE_LINK 1592 +#define _WIN32_IE_IE70 0x0700 +#define _WIN32_IE_IE80 0x0800 +#define CS_SAVEBITS 0x0800 +#define HDS_NOSIZING 0x0800 +#define TBSTYLE_FLAT 0x0800 +#define RBS_FIXEDORDER 0x00000800 +#define SBARS_TOOLTIPS 0x0800 +#define SBT_TOOLTIPS 0x0800 +#define TBS_NOTIFYBEFOREMOVE 0x0800 +#define LVS_ALIGNLEFT 0x0800 +#define TVS_INFOTIP 0x0800 +#define TCS_RAGGEDRIGHT 0x0800 +#define _WIN32_IE_IE90 0x0900 +#define _WIN32_IE_IE100 0x0A00 +#define LVS_ALIGNMASK 0x0c00 +#define CS_BYTEALIGNCLIENT 0x1000 +#define HDS_OVERFLOW 0x1000 +#define TBSTYLE_LIST 0x1000 +#define RBS_REGISTERDROP 0x00001000 +#define TBS_TRANSPARENTBKGND 0x1000 +#define LVS_OWNERDATA 0x1000 +#define TVS_FULLROWSELECT 0x1000 +#define TCS_FOCUSONBUTTONDOWN 0x1000 +#define CS_BYTEALIGNWINDOW 0x2000 +#define TBSTYLE_CUSTOMERASE 0x2000 +#define RBS_AUTOSIZE 0x00002000 +#define LVS_NOSCROLL 0x2000 +#define TVS_NOSCROLL 0x2000 +#define TCS_OWNERDRAWFIXED 0x2000 +#define VER_PRODUCTBUILD 9200 +#define CS_GLOBALCLASS 0x4000 +#define TBSTYLE_REGISTERDROP 0x4000 +#define RBS_VERTICALGRIPPER 0x00004000 +#define LVS_NOCOLUMNHEADER 0x4000 +#define TVS_NONEVENHEIGHT 0x4000 +#define TCS_TOOLTIPS 0x4000 +#define VER_PRODUCTBUILD_QFE 20557 +#define VER_PACKAGEBUILD_QFE 20557 +#define IDH_NO_HELP 28440 +#define IDH_MISSING_CONTEXT 28441 +#define IDH_GENERIC_HELP_BUTTON 28442 +#define IDH_OK 28443 +#define IDH_CANCEL 28444 +#define IDH_HELP 28445 +#define LANG_BOSNIAN_NEUTRAL 0x781a +#define LANG_CHINESE_TRADITIONAL 0x7c04 +#define LANG_SERBIAN_NEUTRAL 0x7c1a +#define IDTIMEOUT 32000 +#define OCR_NORMAL 32512 +#define OIC_SAMPLE 32512 +#define IDI_APPLICATION 32512 +#define OCR_IBEAM 32513 +#define OIC_HAND 32513 +#define IDI_HAND 32513 +#define OCR_WAIT 32514 +#define OIC_QUES 32514 +#define IDI_QUESTION 32514 +#define OCR_CROSS 32515 +#define OIC_BANG 32515 +#define IDI_EXCLAMATION 32515 +#define OCR_UP 32516 +#define OIC_NOTE 32516 +#define IDI_ASTERISK 32516 +#define OIC_WINLOGO 32517 +#define IDI_WINLOGO 32517 +#define OIC_SHIELD 32518 +#define IDI_SHIELD 32518 +#define OCR_SIZE 32640 +#define OCR_ICON 32641 +#define OCR_SIZENWSE 32642 +#define OCR_SIZENESW 32643 +#define OCR_SIZEWE 32644 +#define OCR_SIZENS 32645 +#define OCR_SIZEALL 32646 +#define OCR_ICOCUR 32647 +#define OCR_NO 32648 +#define OCR_HAND 32649 +#define OCR_APPSTARTING 32650 +#define OBM_LFARROWI 32734 +#define OBM_RGARROWI 32735 +#define OBM_DNARROWI 32736 +#define OBM_UPARROWI 32737 +#define OBM_COMBO 32738 +#define OBM_MNARROW 32739 +#define OBM_LFARROWD 32740 +#define OBM_RGARROWD 32741 +#define OBM_DNARROWD 32742 +#define OBM_UPARROWD 32743 +#define OBM_RESTORED 32744 +#define OBM_ZOOMD 32745 +#define OBM_REDUCED 32746 +#define OBM_RESTORE 32747 +#define OBM_ZOOM 32748 +#define OBM_REDUCE 32749 +#define OBM_LFARROW 32750 +#define OBM_RGARROW 32751 +#define OBM_DNARROW 32752 +#define OBM_UPARROW 32753 +#define OBM_CLOSE 32754 +#define OBM_OLD_RESTORE 32755 +#define OBM_OLD_ZOOM 32756 +#define OBM_OLD_REDUCE 32757 +#define OBM_BTNCORNERS 32758 +#define OBM_CHECKBOXES 32759 +#define OBM_CHECK 32760 +#define OBM_BTSIZE 32761 +#define OBM_OLD_LFARROW 32762 +#define OBM_OLD_RGARROW 32763 +#define OBM_OLD_DNARROW 32764 +#define OBM_OLD_UPARROW 32765 +#define OBM_SIZE 32766 +#define OBM_OLD_CLOSE 32767 +#define WM_APP 0x8000 +#define HELP_TCARD 0x8000 +#define TBSTYLE_TRANSPARENT 0x8000 +#define RBS_DBLCLKTOGGLE 0x00008000 +#define LVS_NOSORTHEADER 0x8000 +#define TVS_NOHSCROLL 0x8000 +#define TCS_FOCUSNEVER 0x8000 +#define SC_SIZE 0xF000 +#define SC_SEPARATOR 0xF00F +#define SC_MOVE 0xF010 +#define SC_MINIMIZE 0xF020 +#define SC_MAXIMIZE 0xF030 +#define SC_NEXTWINDOW 0xF040 +#define SC_PREVWINDOW 0xF050 +#define SC_CLOSE 0xF060 +#define SC_VSCROLL 0xF070 +#define SC_HSCROLL 0xF080 +#define SC_MOUSEMENU 0xF090 +#define SC_KEYMENU 0xF100 +#define SC_ARRANGE 0xF110 +#define SC_RESTORE 0xF120 +#define SC_TASKLIST 0xF130 +#define SC_SCREENSAVE 0xF140 +#define SC_HOTKEY 0xF150 +#define SC_DEFAULT 0xF160 +#define SC_MONITORPOWER 0xF170 +#define SC_CONTEXTHELP 0xF180 +#define LVS_TYPESTYLEMASK 0xfc00 +#define SPVERSION_MASK 0x0000FF00 +#define HTERROR -2 +#define PWR_FAIL -1 +#define UNICODE_NOCHAR 0xFFFF +#define HTTRANSPARENT -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/TapDriver6/resource.rc b/windows/TapDriver6/resource.rc new file mode 100644 index 00000000..2b65e2bb --- /dev/null +++ b/windows/TapDriver6/resource.rc @@ -0,0 +1,88 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 3,0,0,0 + PRODUCTVERSION 3,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x9L +#else + FILEFLAGS 0x8L +#endif + FILEOS 0x40004L + FILETYPE 0x3L + FILESUBTYPE 0x6L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "ZeroTier Networks LLC" + VALUE "FileDescription", "ZeroTier One Virtual Network Port" + VALUE "FileVersion", "3.0.0 3/0" + VALUE "InternalName", "zttap300.sys" + VALUE "LegalCopyright", "ZeroTier, Inc., OpenVPN Technologies, Inc." + VALUE "OriginalFilename", "zttap300.sys" + VALUE "ProductName", "ZeroTier One Virtual Network Port" + VALUE "ProductVersion", "3.0.0 3/0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/windows/TapDriver6/rxpath.c b/windows/TapDriver6/rxpath.c new file mode 100644 index 00000000..318bc56a --- /dev/null +++ b/windows/TapDriver6/rxpath.c @@ -0,0 +1,669 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +//====================================================================== +// TAP Receive Path Support +//====================================================================== + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( PAGE, TapDeviceWrite) +#endif // ALLOC_PRAGMA + +//=============================================================== +// Used in cases where internally generated packets such as +// ARP or DHCP replies must be returned to the kernel, to be +// seen as an incoming packet "arriving" on the interface. +//=============================================================== + +VOID +IndicateReceivePacket( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PUCHAR packetData, + __in const unsigned int packetLength + ) +{ + PUCHAR injectBuffer; + + // + // Handle miniport Pause + // --------------------- + // NDIS 6 miniports implement a temporary "Pause" state normally followed + // by the Restart. While in the Pause state it is forbidden for the miniport + // to indicate receive NBLs. + // + // That is: The device interface may be "up", but the NDIS miniport send/receive + // interface may be temporarily "down". + // + // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path + // the code below will simply ignore inject packets passed to the driver while + // the miniport is in the Paused state. + // + // The correct implementation is to go ahead and build the NBLs corresponding + // to the inject packet - but queue them. When Restart is entered the + // queued NBLs would be dequeued and indicated to the host. + // + if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS) + { + DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n", + MINIPORT_INSTANCE_ID (Adapter))); + + return; + } + + // Allocate flat buffer for packet data. + injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority( + Adapter->MiniportAdapterHandle, + packetLength, + TAP_RX_INJECT_BUFFER_TAG, + NormalPoolPriority + ); + + if( injectBuffer) + { + PMDL mdl; + + // Copy packet data to flat buffer. + NdisMoveMemory (injectBuffer, packetData, packetLength); + + // Allocate MDL for flat buffer. + mdl = NdisAllocateMdl( + Adapter->MiniportAdapterHandle, + injectBuffer, + packetLength + ); + + if( mdl ) + { + PNET_BUFFER_LIST netBufferList; + + mdl->Next = NULL; // No next MDL + + // Allocate the NBL and NB. Link MDL chain to NB. + netBufferList = NdisAllocateNetBufferAndNetBufferList( + Adapter->ReceiveNblPool, + 0, // ContextSize + 0, // ContextBackFill + mdl, // MDL chain + 0, + packetLength + ); + + if(netBufferList != NULL) + { + ULONG receiveFlags = 0; + LONG nblCount; + + NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL + + if(KeGetCurrentIrql() == DISPATCH_LEVEL) + { + receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; + } + + // Set flag indicating that this is an injected packet + TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); + TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED); + + netBufferList->MiniportReserved[0] = NULL; + netBufferList->MiniportReserved[1] = NULL; + + // Increment in-flight receive NBL count. + nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0 ); + + netBufferList->SourceHandle = Adapter->MiniportAdapterHandle; + + // + // Indicate the packet + // ------------------- + // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length + // contains the complete packet including Ethernet header and payload. + // + NdisMIndicateReceiveNetBufferLists( + Adapter->MiniportAdapterHandle, + netBufferList, + NDIS_DEFAULT_PORT_NUMBER, + 1, // NumberOfNetBufferLists + receiveFlags + ); + + return; + } + else + { + DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n", + MINIPORT_INSTANCE_ID (Adapter))); + NOTE_ERROR (); + + NdisFreeMdl(mdl); + NdisFreeMemory(injectBuffer,0,0); + } + } + else + { + DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n", + MINIPORT_INSTANCE_ID (Adapter))); + NOTE_ERROR (); + + NdisFreeMemory(injectBuffer,0,0); + } + } + else + { + DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n", + MINIPORT_INSTANCE_ID (Adapter))); + NOTE_ERROR (); + } +} + +VOID +tapCompleteIrpAndFreeReceiveNetBufferList( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER_LIST NetBufferList, // Only one NB here... + __in NTSTATUS IoCompletionStatus + ) +{ + PIRP irp; + ULONG frameType, netBufferCount, byteCount; + LONG nblCount; + + // Fetch NB frame type. + frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList)); + + // Fetch statistics for all NBs linked to the NB. + netBufferCount = tapGetNetBufferCountsFromNetBufferList( + NetBufferList, + &byteCount + ); + + // Update statistics by frame type + if(IoCompletionStatus == STATUS_SUCCESS) + { + switch(frameType) + { + case NDIS_PACKET_TYPE_DIRECTED: + Adapter->FramesRxDirected += netBufferCount; + Adapter->BytesRxDirected += byteCount; + break; + + case NDIS_PACKET_TYPE_BROADCAST: + Adapter->FramesRxBroadcast += netBufferCount; + Adapter->BytesRxBroadcast += byteCount; + break; + + case NDIS_PACKET_TYPE_MULTICAST: + Adapter->FramesRxMulticast += netBufferCount; + Adapter->BytesRxMulticast += byteCount; + break; + + default: + ASSERT(FALSE); + break; + } + } + + // + // Handle P2P Packet + // ----------------- + // Free MDL allocated for P2P Ethernet header. + // + if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P)) + { + PNET_BUFFER netBuffer; + PMDL mdl; + + netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + mdl = NET_BUFFER_FIRST_MDL(netBuffer); + mdl->Next = NULL; + + NdisFreeMdl(mdl); + } + + // + // Handle Injected Packet + // ----------------------- + // Free MDL and data buffer allocated for injected packet. + // + if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED)) + { + PNET_BUFFER netBuffer; + PMDL mdl; + PUCHAR injectBuffer; + + netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + mdl = NET_BUFFER_FIRST_MDL(netBuffer); + + injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority); + + if(injectBuffer) + { + NdisFreeMemory(injectBuffer,0,0); + } + + NdisFreeMdl(mdl); + } + + // + // Complete the IRP + // + irp = (PIRP )NetBufferList->MiniportReserved[0]; + + if(irp) + { + irp->IoStatus.Status = IoCompletionStatus; + IoCompleteRequest(irp, IO_NO_INCREMENT); + } + + // Decrement in-flight receive NBL count. + nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount >= 0 ); + if (0 == nblCount) + { + NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); + } + + // Free the NBL + NdisFreeNetBufferList(NetBufferList); +} + +VOID +AdapterReturnNetBufferLists( + __in NDIS_HANDLE MiniportAdapterContext, + __in PNET_BUFFER_LIST NetBufferLists, + __in ULONG ReturnFlags + ) +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + PNET_BUFFER_LIST currentNbl, nextNbl; + + UNREFERENCED_PARAMETER(ReturnFlags); + + // + // Process each NBL individually + // + currentNbl = NetBufferLists; + while (currentNbl) + { + PNET_BUFFER_LIST nextNbl; + + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL; + + // Complete write IRP and free NBL and associated resources. + tapCompleteIrpAndFreeReceiveNetBufferList( + adapter, + currentNbl, + STATUS_SUCCESS + ); + + // Move to next NBL + currentNbl = nextNbl; + } +} + +// IRP_MJ_WRITE callback. +NTSTATUS +TapDeviceWrite( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +{ + NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success + PIO_STACK_LOCATION irpSp;// Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + ULONG dataLength; + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation( Irp ); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; + + ASSERT(adapter); + + // + // Sanity checks on state variables + // + if (!tapAdapterReadAndWriteReady(adapter)) + { + //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", + // MINIPORT_INSTANCE_ID (adapter))); + //NOTE_ERROR(); + + Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // Save IRP-accessible copy of buffer length + Irp->IoStatus.Information = irpSp->Parameters.Write.Length; + + if (Irp->MdlAddress == NULL) + { + DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID (adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // + // Try to get a virtual address for the MDL. + // + NdisQueryMdl( + Irp->MdlAddress, + &Irp->AssociatedIrp.SystemBuffer, + &dataLength, + NormalPagePriority + ); + + if (Irp->AssociatedIrp.SystemBuffer == NULL) + { + DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID (adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + ASSERT(dataLength == irpSp->Parameters.Write.Length); + + Irp->IoStatus.Information = irpSp->Parameters.Write.Length; + + // + // Handle miniport Pause + // --------------------- + // NDIS 6 miniports implement a temporary "Pause" state normally followed + // by the Restart. While in the Pause state it is forbidden for the miniport + // to indicate receive NBLs. + // + // That is: The device interface may be "up", but the NDIS miniport send/receive + // interface may be temporarily "down". + // + // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path + // the code below will perform a "lying send" for write IRPs passed to the + // driver while the miniport is in the Paused state. + // + // The correct implementation is to go ahead and build the NBLs corresponding + // to the user-mode write - but queue them. When Restart is entered the + // queued NBLs would be dequeued and indicated to the host. + // + if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) + { + if (/*!adapter->m_tun &&*/ ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) + { + PNET_BUFFER_LIST netBufferList; + + DUMP_PACKET ("IRP_MJ_WRITE ETH", + (unsigned char *) Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify ( + (unsigned char *) Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length, + FALSE, + "RX", + &adapter->m_RxTrunc + ); +#endif + (Irp->MdlAddress)->Next = NULL; // No next MDL + + // Allocate the NBL and NB. Link MDL chain to NB. + netBufferList = NdisAllocateNetBufferAndNetBufferList( + adapter->ReceiveNblPool, + 0, // ContextSize + 0, // ContextBackFill + Irp->MdlAddress, // MDL chain + 0, + dataLength + ); + + if(netBufferList != NULL) + { + LONG nblCount; + + NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL + + // Stash IRP pointer in NBL MiniportReserved[0] field. + netBufferList->MiniportReserved[0] = Irp; + netBufferList->MiniportReserved[1] = NULL; + + // This IRP is pended. + IoMarkIrpPending(Irp); + + // This IRP cannot be cancelled while in-flight. + IoSetCancelRoutine(Irp,NULL); + + TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); + + // Increment in-flight receive NBL count. + nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0 ); + + // + // Indicate the packet + // ------------------- + // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length + // contains the complete packet including Ethernet header and payload. + // + NdisMIndicateReceiveNetBufferLists( + adapter->MiniportAdapterHandle, + netBufferList, + NDIS_DEFAULT_PORT_NUMBER, + 1, // NumberOfNetBufferLists + 0 // ReceiveFlags + ); + + ntStatus = STATUS_PENDING; + } + else + { + DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID (adapter))); + NOTE_ERROR (); + + // Fail the IRP + Irp->IoStatus.Information = 0; + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + /* + else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) + { + PETH_HEADER p_UserToTap = &adapter->m_UserToTap; + PMDL mdl; // Head of MDL chain. + + // For IPv6, need to use Ethernet header with IPv6 proto + if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 ) + { + p_UserToTap = &adapter->m_UserToTap_IPv6; + } + + DUMP_PACKET2 ("IRP_MJ_WRITE P2P", + p_UserToTap, + (unsigned char *) Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify ( + (unsigned char *) Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length, + TRUE, + "RX", + &adapter->m_RxTrunc + ); +#endif + + // + // Allocate MDL for Ethernet header + // -------------------------------- + // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length + // contains the only the Ethernet payload. Prepend the user-mode provided + // payload with the Ethernet header pointed to by p_UserToTap. + // + mdl = NdisAllocateMdl( + adapter->MiniportAdapterHandle, + p_UserToTap, + sizeof(ETH_HEADER) + ); + + if(mdl != NULL) + { + PNET_BUFFER_LIST netBufferList; + + // Chain user's Ethernet payload behind Ethernet header. + mdl->Next = Irp->MdlAddress; + (Irp->MdlAddress)->Next = NULL; // No next MDL + + // Allocate the NBL and NB. Link MDL chain to NB. + netBufferList = NdisAllocateNetBufferAndNetBufferList( + adapter->ReceiveNblPool, + 0, // ContextSize + 0, // ContextBackFill + mdl, // MDL chain + 0, + sizeof(ETH_HEADER) + dataLength + ); + + if(netBufferList != NULL) + { + LONG nblCount; + + NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL + + // This IRP is pended. + IoMarkIrpPending(Irp); + + // This IRP cannot be cancelled while in-flight. + IoSetCancelRoutine(Irp,NULL); + + // Stash IRP pointer in NBL MiniportReserved[0] field. + netBufferList->MiniportReserved[0] = Irp; + netBufferList->MiniportReserved[1] = NULL; + + // Set flag indicating that this is P2P packet + TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); + TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P); + + // Increment in-flight receive NBL count. + nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0 ); + + // + // Indicate the packet + // + NdisMIndicateReceiveNetBufferLists( + adapter->MiniportAdapterHandle, + netBufferList, + NDIS_DEFAULT_PORT_NUMBER, + 1, // NumberOfNetBufferLists + 0 // ReceiveFlags + ); + + ntStatus = STATUS_PENDING; + } + else + { + mdl->Next = NULL; + NdisFreeMdl(mdl); + + DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID (adapter))); + NOTE_ERROR (); + + // Fail the IRP + Irp->IoStatus.Information = 0; + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID (adapter))); + NOTE_ERROR (); + + // Fail the IRP + Irp->IoStatus.Information = 0; + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + */ + else + { + DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", + MINIPORT_INSTANCE_ID (adapter), + irpSp->Parameters.Write.Length)); + NOTE_ERROR (); + + Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } + else + { + DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n", + MINIPORT_INSTANCE_ID (adapter))); + + ntStatus = STATUS_SUCCESS; + } + + if (ntStatus != STATUS_PENDING) + { + Irp->IoStatus.Status = ntStatus; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return ntStatus; +} + diff --git a/windows/TapDriver6/tap-windows.h b/windows/TapDriver6/tap-windows.h new file mode 100644 index 00000000..7e01846d --- /dev/null +++ b/windows/TapDriver6/tap-windows.h @@ -0,0 +1,81 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_WIN_H +#define __TAP_WIN_H + +/* + * ============= + * TAP IOCTLs + * ============= + */ + +#define TAP_WIN_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +/* Present in 8.1 */ + +#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED) +//#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED) +//#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED) +//#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED) +//#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED) +//#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED) + +/* Added in 8.2 */ + +/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */ +//#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED) + +// Used by ZT1 to get multicast memberships at the L2 level -- Windows provides no native way to do this that I know of +#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS TAP_WIN_CONTROL_CODE (11, METHOD_BUFFERED) +// Must be the same as NIC_MAX_MCAST_LIST in constants.h +#define TAP_MAX_MCAST_LIST 128 +// Amount of memory that must be provided to ioctl TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS +#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE (TAP_MAX_MCAST_LIST * 6) + +/* + * ================= + * Registry keys + * ================= + */ + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +/* + * ====================== + * Filesystem prefixes + * ====================== + */ + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAP_WIN_SUFFIX ".tap" + +#endif // __TAP_WIN_H diff --git a/windows/TapDriver6/tap.h b/windows/TapDriver6/tap.h new file mode 100644 index 00000000..079b279f --- /dev/null +++ b/windows/TapDriver6/tap.h @@ -0,0 +1,88 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_H +#define __TAP_H + +#ifndef NDIS_SUPPORT_NDIS6 +#define NDIS_SUPPORT_NDIS6 1 +#define NDIS_SUPPORT_NDIS61 1 +#define NDIS_WDM1 1 +#define NDIS61_MINIPORT 1 +#endif + +#include <ntifs.h> +#include <ndis.h> +#include <ntstrsafe.h> +#include <netioapi.h> + +#include "config.h" +#include "lock.h" +#include "constants.h" +#include "proto.h" +#include "mem.h" +#include "macinfo.h" +#include "error.h" +#include "endian.h" +#include "types.h" +#include "adapter.h" +#include "device.h" +#include "prototypes.h" +#include "tap-windows.h" + +//======================================================== +// Check for truncated IPv4 packets, log errors if found. +//======================================================== +#define PACKET_TRUNCATION_CHECK 0 + +//======================================================== +// EXPERIMENTAL -- Configure TAP device object to be +// accessible from non-administrative accounts, based +// on an advanced properties setting. +// +// Duplicates the functionality of OpenVPN's +// --allow-nonadmin directive. +//======================================================== +#define ENABLE_NONADMIN 1 + +// +// The driver has exactly one instance of the TAP_GLOBAL structure. NDIS keeps +// an opaque handle to this data, (it doesn't attempt to read or interpret this +// data), and it passes the handle back to the miniport in MiniportSetOptions +// and MiniportInitializeEx. +// +typedef struct _TAP_GLOBAL +{ + LIST_ENTRY AdapterList; + + NDIS_RW_LOCK Lock; + + NDIS_HANDLE NdisDriverHandle; // From NdisMRegisterMiniportDriver + +} TAP_GLOBAL, *PTAP_GLOBAL; + + +// Global data +extern TAP_GLOBAL GlobalData; + +#endif // __TAP_H diff --git a/windows/TapDriver6/tapdrvr.c b/windows/TapDriver6/tapdrvr.c new file mode 100644 index 00000000..6c537f1d --- /dev/null +++ b/windows/TapDriver6/tapdrvr.c @@ -0,0 +1,232 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//====================================================== +// This driver is designed to work on Windows Vista or higher +// versions of Windows. +// +// It is SMP-safe and handles power management. +// +// By default we operate as a "tap" virtual ethernet +// 802.3 interface, but we can emulate a "tun" +// interface (point-to-point IPv4) through the +// TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT or +// TAP_WIN_IOCTL_CONFIG_TUN ioctl. +//====================================================== + +// +// Include files. +// + +#include <string.h> + +#include "tap.h" + + +// Global data +TAP_GLOBAL GlobalData; + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( INIT, DriverEntry ) +#pragma alloc_text( PAGE, TapDriverUnload) +#endif // ALLOC_PRAGMA + +NTSTATUS +DriverEntry( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath + ) +/*++ +Routine Description: + + In the context of its DriverEntry function, a miniport driver associates + itself with NDIS, specifies the NDIS version that it is using, and + registers its entry points. + + +Arguments: + PVOID DriverObject - pointer to the driver object. + PVOID RegistryPath - pointer to the driver registry path. + + Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(RegistryPath); + + DEBUGP (("[TAP] --> DriverEntry; version [%d.%d] %s %s\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + __DATE__, + __TIME__)); + + DEBUGP (("[TAP] Registry Path: '%wZ'\n", RegistryPath)); + + // + // Initialize any driver-global variables here. + // + NdisZeroMemory(&GlobalData, sizeof(GlobalData)); + + // + // The ApaterList in the GlobalData structure is used to track multiple + // adapters controlled by this miniport. + // + NdisInitializeListHead(&GlobalData.AdapterList); + + // + // This lock protects the AdapterList. + // + NdisInitializeReadWriteLock(&GlobalData.Lock); + + do + { + NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniportCharacteristics; + + NdisZeroMemory(&miniportCharacteristics, sizeof(miniportCharacteristics)); + + {C_ASSERT(sizeof(miniportCharacteristics) >= NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2);} + miniportCharacteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS; + miniportCharacteristics.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; + miniportCharacteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; + + miniportCharacteristics.MajorNdisVersion = TAP_NDIS_MAJOR_VERSION; + miniportCharacteristics.MinorNdisVersion = TAP_NDIS_MINOR_VERSION; + + miniportCharacteristics.MajorDriverVersion = TAP_DRIVER_MAJOR_VERSION; + miniportCharacteristics.MinorDriverVersion = TAP_DRIVER_MINOR_VERSION; + + miniportCharacteristics.Flags = 0; + + //miniportCharacteristics.SetOptionsHandler = MPSetOptions; // Optional + miniportCharacteristics.InitializeHandlerEx = AdapterCreate; + miniportCharacteristics.HaltHandlerEx = AdapterHalt; + miniportCharacteristics.UnloadHandler = TapDriverUnload; + miniportCharacteristics.PauseHandler = AdapterPause; + miniportCharacteristics.RestartHandler = AdapterRestart; + miniportCharacteristics.OidRequestHandler = AdapterOidRequest; + miniportCharacteristics.SendNetBufferListsHandler = AdapterSendNetBufferLists; + miniportCharacteristics.ReturnNetBufferListsHandler = AdapterReturnNetBufferLists; + miniportCharacteristics.CancelSendHandler = AdapterCancelSend; + miniportCharacteristics.CheckForHangHandlerEx = AdapterCheckForHangEx; + miniportCharacteristics.ResetHandlerEx = AdapterReset; + miniportCharacteristics.DevicePnPEventNotifyHandler = AdapterDevicePnpEventNotify; + miniportCharacteristics.ShutdownHandlerEx = AdapterShutdownEx; + miniportCharacteristics.CancelOidRequestHandler = AdapterCancelOidRequest; + + // + // Associate the miniport driver with NDIS by calling the + // NdisMRegisterMiniportDriver. This function returns an NdisDriverHandle. + // The miniport driver must retain this handle but it should never attempt + // to access or interpret this handle. + // + // By calling NdisMRegisterMiniportDriver, the driver indicates that it + // is ready for NDIS to call the driver's MiniportSetOptions and + // MiniportInitializeEx handlers. + // + DEBUGP (("[TAP] Calling NdisMRegisterMiniportDriver...\n")); + //NDIS_DECLARE_MINIPORT_DRIVER_CONTEXT(TAP_GLOBAL); + status = NdisMRegisterMiniportDriver( + DriverObject, + RegistryPath, + &GlobalData, + &miniportCharacteristics, + &GlobalData.NdisDriverHandle + ); + + if (NDIS_STATUS_SUCCESS == status) + { + DEBUGP (("[TAP] Registered miniport successfully\n")); + } + else + { + DEBUGP(("[TAP] NdisMRegisterMiniportDriver failed: %8.8X\n", status)); + TapDriverUnload(DriverObject); + status = NDIS_STATUS_FAILURE; + break; + } + } while(FALSE); + + DEBUGP (("[TAP] <-- DriverEntry; status = %8.8X\n",status)); + + return status; +} + +VOID +TapDriverUnload( + __in PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + The unload handler is called during driver unload to free up resources + acquired in DriverEntry. This handler is registered in DriverEntry through + NdisMRegisterMiniportDriver. Note that an unload handler differs from + a MiniportHalt function in that this unload handler releases resources that + are global to the driver, while the halt handler releases resource for a + particular adapter. + + Runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + DriverObject Not used + +Return Value: + + None. + +--*/ +{ + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + UNICODE_STRING uniWin32NameString; + + DEBUGP (("[TAP] --> TapDriverUnload; version [%d.%d] %s %s unloaded\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + __DATE__, + __TIME__ + )); + + PAGED_CODE(); + + // + // Clean up all globals that were allocated in DriverEntry + // + + ASSERT(IsListEmpty(&GlobalData.AdapterList)); + + if(GlobalData.NdisDriverHandle != NULL ) + { + NdisMDeregisterMiniportDriver(GlobalData.NdisDriverHandle); + } + + DEBUGP (("[TAP] <-- TapDriverUnload\n")); +} + diff --git a/windows/TapDriver6/txpath.c b/windows/TapDriver6/txpath.c new file mode 100644 index 00000000..7993ca40 --- /dev/null +++ b/windows/TapDriver6/txpath.c @@ -0,0 +1,1175 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +//====================================================================== +// TAP Send Path Support +//====================================================================== + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( PAGE, TapDeviceRead) +#endif // ALLOC_PRAGMA + +// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum +// see RFC 4443, 2.3, and RFC 2460, 8.1 +USHORT +icmpv6_checksum( + __in const UCHAR *buf, + __in const int len_icmpv6, + __in const UCHAR *saddr6, + __in const UCHAR *daddr6 + ) +{ + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words and + // calculate the sum of all 16 bit words + for (i = 0; i < len_icmpv6; i += 2) + { + word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0); + sum += word16; + } + + // add the IPv6 pseudo header which contains the IP source and destination addresses + for (i = 0; i < 16; i += 2) + { + word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF); + sum += word16; + } + + for (i = 0; i < 16; i += 2) + { + word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF); + sum += word16; + } + + // the next-header number and the length of the ICMPv6 packet + sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6; + + // keep only the last 16 bits of the 32 bit calculated sum and add the carries + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + // Take the one's complement of sum + return ((USHORT) ~sum); +} + +/* + +// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that +// the tap driver needs to answer?" +// see RFC 4861 4.3 for the different cases +static IPV6ADDR IPV6_NS_TARGET_MCAST = + { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 }; +static IPV6ADDR IPV6_NS_TARGET_UNICAST = + { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 }; + +BOOLEAN +HandleIPv6NeighborDiscovery( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in UCHAR * m_Data + ) +{ + const ETH_HEADER * e = (ETH_HEADER *) m_Data; + const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER)); + const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR)); + ICMPV6_NA_PKT *na; + USHORT icmpv6_len, icmpv6_csum; + + // we don't really care about the destination MAC address here + // - it's either a multicast MAC, or the userland destination MAC + // but since the TAP driver is point-to-point, all packets are "for us" + + // IPv6 target address must be ff02::1::ff00:8 (multicast for + // initial NS) or fe80::1 (unicast for recurrent NUD) + if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST, + sizeof(IPV6ADDR) ) != 0 && + memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST, + sizeof(IPV6ADDR) ) != 0 ) + { + return FALSE; // wrong target address + } + + // IPv6 Next-Header must be ICMPv6 + if ( ipv6->nexthdr != IPPROTO_ICMPV6 ) + { + return FALSE; // wrong next-header + } + + // ICMPv6 type+code must be 135/0 for NS + if ( icmpv6_ns->type != ICMPV6_TYPE_NS || + icmpv6_ns->code != ICMPV6_CODE_0 ) + { + return FALSE; // wrong ICMPv6 type + } + + // ICMPv6 target address must be fe80::8 (magic) + if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST, + sizeof(IPV6ADDR) ) != 0 ) + { + return FALSE; // not for us + } + + // packet identified, build magic response packet + + na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE); + if ( !na ) return FALSE; + + //------------------------------------------------ + // Initialize Neighbour Advertisement reply packet + //------------------------------------------------ + + // ethernet header + na->eth.proto = htons(NDIS_ETH_TYPE_IPV6); + ETH_COPY_NETWORK_ADDRESS(na->eth.dest, Adapter->PermanentAddress); + ETH_COPY_NETWORK_ADDRESS(na->eth.src, Adapter->m_TapToUser.dest); + + // IPv6 header + na->ipv6.version_prio = ipv6->version_prio; + NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl, + sizeof(na->ipv6.flow_lbl) ); + icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR); + na->ipv6.payload_len = htons(icmpv6_len); + na->ipv6.nexthdr = IPPROTO_ICMPV6; + na->ipv6.hop_limit = 255; + NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST, + sizeof(IPV6ADDR) ); + NdisMoveMemory( na->ipv6.daddr, ipv6->saddr, + sizeof(IPV6ADDR) ); + + // ICMPv6 + na->icmpv6.type = ICMPV6_TYPE_NA; + na->icmpv6.code = ICMPV6_CODE_0; + na->icmpv6.checksum = 0; + na->icmpv6.rso_bits = 0x60; // Solicited + Override + NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) ); + NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST, + sizeof(IPV6ADDR) ); + + // ICMPv6 option "Target Link Layer Address" + na->icmpv6.opt_type = ICMPV6_OPTION_TLLA; + na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA; + ETH_COPY_NETWORK_ADDRESS( na->icmpv6.target_macaddr, Adapter->m_TapToUser.dest ); + + // calculate and set checksum + icmpv6_csum = icmpv6_checksum ( + (UCHAR*) &(na->icmpv6), + icmpv6_len, + na->ipv6.saddr, + na->ipv6.daddr + ); + + na->icmpv6.checksum = htons( icmpv6_csum ); + + DUMP_PACKET ("HandleIPv6NeighborDiscovery", + (unsigned char *) na, + sizeof (ICMPV6_NA_PKT)); + + IndicateReceivePacket (Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT)); + + MemFree (na, sizeof (ICMPV6_NA_PKT)); + + return TRUE; // all fine +} + +//=================================================== +// Generate an ARP reply message for specific kinds +// ARP queries. +//=================================================== +BOOLEAN +ProcessARP( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in const PARP_PACKET src, + __in const IPADDR adapter_ip, + __in const IPADDR ip_network, + __in const IPADDR ip_netmask, + __in const MACADDR mac + ) +{ + //----------------------------------------------- + // Is this the kind of packet we are looking for? + //----------------------------------------------- + if (src->m_Proto == htons (NDIS_ETH_TYPE_ARP) + && MAC_EQUAL (src->m_MAC_Source, Adapter->PermanentAddress) + && MAC_EQUAL (src->m_ARP_MAC_Source, Adapter->PermanentAddress) + && ETH_IS_BROADCAST(src->m_MAC_Destination) + && src->m_ARP_Operation == htons (ARP_REQUEST) + && src->m_MAC_AddressType == htons (MAC_ADDR_TYPE) + && src->m_MAC_AddressSize == sizeof (MACADDR) + && src->m_PROTO_AddressType == htons (NDIS_ETH_TYPE_IPV4) + && src->m_PROTO_AddressSize == sizeof (IPADDR) + && src->m_ARP_IP_Source == adapter_ip + && (src->m_ARP_IP_Destination & ip_netmask) == ip_network + && src->m_ARP_IP_Destination != adapter_ip) + { + ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE); + if (arp) + { + //---------------------------------------------- + // Initialize ARP reply fields + //---------------------------------------------- + arp->m_Proto = htons (NDIS_ETH_TYPE_ARP); + arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE); + arp->m_PROTO_AddressType = htons (NDIS_ETH_TYPE_IPV4); + arp->m_MAC_AddressSize = sizeof (MACADDR); + arp->m_PROTO_AddressSize = sizeof (IPADDR); + arp->m_ARP_Operation = htons (ARP_REPLY); + + //---------------------------------------------- + // ARP addresses + //---------------------------------------------- + ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Source, mac); + ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Destination, Adapter->PermanentAddress); + ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Source, mac); + ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Destination, Adapter->PermanentAddress); + arp->m_ARP_IP_Source = src->m_ARP_IP_Destination; + arp->m_ARP_IP_Destination = adapter_ip; + + DUMP_PACKET ("ProcessARP", + (unsigned char *) arp, + sizeof (ARP_PACKET)); + + IndicateReceivePacket (Adapter, (UCHAR *) arp, sizeof (ARP_PACKET)); + + MemFree (arp, sizeof (ARP_PACKET)); + } + + return TRUE; + } + else + return FALSE; +} +*/ + +//============================================================= +// CompleteIRP is normally called with an adapter -> userspace +// network packet and an IRP (Pending I/O request) from userspace. +// +// The IRP will normally represent a queued overlapped read +// operation from userspace that is in a wait state. +// +// Use the ethernet packet to satisfy the IRP. +//============================================================= + +VOID +tapCompletePendingReadIrp( + __in PIRP Irp, + __in PTAP_PACKET TapPacket + ) +{ + int offset; + int len; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + ASSERT(Irp); + ASSERT(TapPacket); + + //------------------------------------------- + // While TapPacket always contains a + // full ethernet packet, including the + // ethernet header, in point-to-point mode, + // we only want to return the IPv4 + // component. + //------------------------------------------- + + if (TapPacket->m_SizeFlags & TP_TUN) + { + offset = ETHERNET_HEADER_SIZE; + len = (int) (TapPacket->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE; + } + else + { + offset = 0; + len = (TapPacket->m_SizeFlags & TP_SIZE_MASK); + } + + if (len < 0 || (int) Irp->IoStatus.Information < len) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status = STATUS_BUFFER_OVERFLOW; + NOTE_ERROR (); + } + else + { + Irp->IoStatus.Information = len; + Irp->IoStatus.Status = status = STATUS_SUCCESS; + + // Copy packet data + NdisMoveMemory( + Irp->AssociatedIrp.SystemBuffer, + TapPacket->m_Data + offset, + len + ); + } + + // Free the TAP packet + NdisFreeMemory(TapPacket,0,0); + + // Complete the IRP + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); +} + +VOID +tapProcessSendPacketQueue( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + KIRQL irql; + + // Process the send packet queue + KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); + + while(Adapter->SendPacketQueue.Count > 0 ) + { + PIRP irp; + PTAP_PACKET tapPacket; + + // Fetch a read IRP + irp = IoCsqRemoveNextIrp( + &Adapter->PendingReadIrpQueue.CsqQueue, + NULL + ); + + if( irp == NULL ) + { + // No IRP to satisfy + break; + } + + // Fetch a queued TAP send packet + tapPacket = tapPacketRemoveHeadLocked( + &Adapter->SendPacketQueue + ); + + ASSERT(tapPacket); + + // BUGBUG!!! Investigate whether release/reacquire can cause + // out-of-order IRP completion. Also, whether user-mode can + // tolerate out-of-order packets. + + // Release packet queue lock while completing the IRP + //KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); + + // Complete the read IRP from queued TAP send packet. + tapCompletePendingReadIrp(irp,tapPacket); + + // Reqcquire packet queue lock after completing the IRP + //KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); + } + + KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); +} + +// Flush the pending send TAP packet queue. +VOID +tapFlushSendPacketQueue( + __in PTAP_ADAPTER_CONTEXT Adapter + ) +{ + KIRQL irql; + + // Process the send packet queue + KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); + + DEBUGP (("[TAP] tapFlushSendPacketQueue: Flushing %d TAP packets\n", + Adapter->SendPacketQueue.Count)); + + while(Adapter->SendPacketQueue.Count > 0 ) + { + PTAP_PACKET tapPacket; + + // Fetch a queued TAP send packet + tapPacket = tapPacketRemoveHeadLocked( + &Adapter->SendPacketQueue + ); + + ASSERT(tapPacket); + + // Free the TAP packet + NdisFreeMemory(tapPacket,0,0); + } + + KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); +} + +VOID +tapAdapterTransmit( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER NetBuffer, + __in BOOLEAN DispatchLevel + ) +/*++ + +Routine Description: + + This routine is called to transmit an individual net buffer using a + style similar to the previous NDIS 5 AdapterTransmit function. + + In this implementation adapter state and NB length checks have already + been done before this function has been called. + + The net buffer will be completed by the calling routine after this + routine exits. So, under this design it is necessary to make a deep + copy of frame data in the net buffer. + + This routine creates a flat buffer copy of NB frame data. This is an + unnecessary performance bottleneck. However, the bottleneck is probably + not significant or measurable except for adapters running at 1Gbps or + greater speeds. Since this adapter is currently running at 100Mbps this + defect can be ignored. + + Runs at IRQL <= DISPATCH_LEVEL + +Arguments: + + Adapter Pointer to our adapter context + NetBuffer Pointer to the net buffer to transmit + DispatchLevel TRUE if called at IRQL == DISPATCH_LEVEL + +Return Value: + + None. + + In the Microsoft NDIS 6 architecture there is no per-packet status. + +--*/ +{ + NDIS_STATUS status; + ULONG packetLength; + PTAP_PACKET tapPacket; + PVOID packetData; + + packetLength = NET_BUFFER_DATA_LENGTH(NetBuffer); + + // Allocate TAP packet memory + tapPacket = (PTAP_PACKET )NdisAllocateMemoryWithTagPriority( + Adapter->MiniportAdapterHandle, + TAP_PACKET_SIZE (packetLength), + TAP_PACKET_TAG, + NormalPoolPriority + ); + + if(tapPacket == NULL) + { + DEBUGP (("[TAP] tapAdapterTransmit: TAP packet allocation failed\n")); + return; + } + + tapPacket->m_SizeFlags = (packetLength & TP_SIZE_MASK); + + // + // Reassemble packet contents + // -------------------------- + // NdisGetDataBuffer does most of the work. There are two cases: + // + // 1.) If the NB data was not contiguous it will copy the entire + // NB's data to m_data and return pointer to m_data. + // 2.) If the NB data was contiguous it returns a pointer to the + // first byte of the contiguous data instead of a pointer to m_Data. + // In this case the data will not have been copied to m_Data. Copy + // to m_Data will need to be done in an extra step. + // + // Case 1.) is the most likely in normal operation. + // + packetData = NdisGetDataBuffer(NetBuffer,packetLength,tapPacket->m_Data,1,0); + + if(packetData == NULL) + { + DEBUGP (("[TAP] tapAdapterTransmit: Could not get packet data\n")); + + NdisFreeMemory(tapPacket,0,0); + + return; + } + + if(packetData != tapPacket->m_Data) + { + // Packet data was contiguous and not yet copied to m_Data. + NdisMoveMemory(tapPacket->m_Data,packetData,packetLength); + } + + DUMP_PACKET ("AdapterTransmit", tapPacket->m_Data, packetLength); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify( + tapPacket->m_Data, + packetLength, + FALSE, + "TX", + &Adapter->m_TxTrunc + ); +#endif + + //===================================================== + // Are we running in DHCP server masquerade mode? + // + // If so, catch both DHCP requests and ARP queries + // to resolve the address of our virtual DHCP server. + //===================================================== +#if 0 + if (Adapter->m_dhcp_enabled) + { + const ETH_HEADER *eth = (ETH_HEADER *) tapPacket->m_Data; + const IPHDR *ip = (IPHDR *) (tapPacket->m_Data + sizeof (ETH_HEADER)); + const UDPHDR *udp = (UDPHDR *) (tapPacket->m_Data + sizeof (ETH_HEADER) + sizeof (IPHDR)); + + // ARP packet? + if (packetLength == sizeof (ARP_PACKET) + && eth->proto == htons (NDIS_ETH_TYPE_ARP) + && Adapter->m_dhcp_server_arp + ) + { + if (ProcessARP( + Adapter, + (PARP_PACKET) tapPacket->m_Data, + Adapter->m_dhcp_addr, + Adapter->m_dhcp_server_ip, + ~0, + Adapter->m_dhcp_server_mac) + ) + { + goto no_queue; + } + } + + // DHCP packet? + else if (packetLength >= sizeof (ETH_HEADER) + sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + && eth->proto == htons (NDIS_ETH_TYPE_IPV4) + && ip->version_len == 0x45 // IPv4, 20 byte header + && ip->protocol == IPPROTO_UDP + && udp->dest == htons (BOOTPS_PORT) + ) + { + const DHCP *dhcp = (DHCP *) (tapPacket->m_Data + + sizeof (ETH_HEADER) + + sizeof (IPHDR) + + sizeof (UDPHDR)); + + const int optlen = packetLength + - sizeof (ETH_HEADER) + - sizeof (IPHDR) + - sizeof (UDPHDR) + - sizeof (DHCP); + + if (optlen > 0) // we must have at least one DHCP option + { + if (ProcessDHCP (Adapter, eth, ip, udp, dhcp, optlen)) + { + goto no_queue; + } + } + else + { + goto no_queue; + } + } + } +#endif + + //=============================================== + // In Point-To-Point mode, check to see whether + // packet is ARP (handled) or IPv4 (sent to app). + // IPv6 packets are inspected for neighbour discovery + // (to be handled locally), and the rest is forwarded + // all other protocols are dropped + //=============================================== +#if 0 + if (Adapter->m_tun) + { + ETH_HEADER *e; + + e = (ETH_HEADER *) tapPacket->m_Data; + + switch (ntohs (e->proto)) + { + case NDIS_ETH_TYPE_ARP: + + // Make sure that packet is the right size for ARP. + if (packetLength != sizeof (ARP_PACKET)) + { + goto no_queue; + } + + ProcessARP ( + Adapter, + (PARP_PACKET) tapPacket->m_Data, + Adapter->m_localIP, + Adapter->m_remoteNetwork, + Adapter->m_remoteNetmask, + Adapter->m_TapToUser.dest + ); + + default: + goto no_queue; + + case NDIS_ETH_TYPE_IPV4: + + // Make sure that packet is large enough to be IPv4. + if (packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)) + { + goto no_queue; + } + + // Only accept directed packets, not broadcasts. + if (memcmp (e, &Adapter->m_TapToUser, ETHERNET_HEADER_SIZE)) + { + goto no_queue; + } + + // Packet looks like IPv4, queue it. :-) + tapPacket->m_SizeFlags |= TP_TUN; + break; + + case NDIS_ETH_TYPE_IPV6: + // Make sure that packet is large enough to be IPv6. + if (packetLength < (ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE)) + { + goto no_queue; + } + + // Broadcasts and multicasts are handled specially + // (to be implemented) + + // Neighbor discovery packets to fe80::8 are special + // OpenVPN sets this next-hop to signal "handled by tapdrv" + if ( HandleIPv6NeighborDiscovery(Adapter,tapPacket->m_Data) ) + { + goto no_queue; + } + + // Packet looks like IPv6, queue it. :-) + tapPacket->m_SizeFlags |= TP_TUN; + } + } +#endif + + //=============================================== + // Push packet onto queue to wait for read from + // userspace. + //=============================================== + if(tapAdapterReadAndWriteReady(Adapter)) + { + tapPacketQueueInsertTail(&Adapter->SendPacketQueue,tapPacket); + } + else + { + // + // Tragedy. All this work and the packet is of no use... + // + NdisFreeMemory(tapPacket,0,0); + } + + // Return after queuing or freeing TAP packet. + return; + + // Free TAP packet without queuing. +no_queue: + if(tapPacket != NULL ) + { + NdisFreeMemory(tapPacket,0,0); + } + +exit_success: + return; +} + +VOID +tapSendNetBufferListsComplete( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER_LIST NetBufferLists, + __in NDIS_STATUS SendCompletionStatus, + __in BOOLEAN DispatchLevel + ) +{ + PNET_BUFFER_LIST currentNbl; + PNET_BUFFER_LIST nextNbl = NULL; + ULONG sendCompleteFlags = 0; + + for ( + currentNbl = NetBufferLists; + currentNbl != NULL; + currentNbl = nextNbl + ) + { + ULONG frameType; + ULONG netBufferCount; + ULONG byteCount; + + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + + // Set NBL completion status. + NET_BUFFER_LIST_STATUS(currentNbl) = SendCompletionStatus; + + // Fetch first NBs frame type. All linked NBs will have same type. + frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(currentNbl)); + + // Fetch statistics for all NBs linked to the NB. + netBufferCount = tapGetNetBufferCountsFromNetBufferList( + currentNbl, + &byteCount + ); + + // Update statistics by frame type + if(SendCompletionStatus == NDIS_STATUS_SUCCESS) + { + switch(frameType) + { + case NDIS_PACKET_TYPE_DIRECTED: + Adapter->FramesTxDirected += netBufferCount; + Adapter->BytesTxDirected += byteCount; + break; + + case NDIS_PACKET_TYPE_BROADCAST: + Adapter->FramesTxBroadcast += netBufferCount; + Adapter->BytesTxBroadcast += byteCount; + break; + + case NDIS_PACKET_TYPE_MULTICAST: + Adapter->FramesTxMulticast += netBufferCount; + Adapter->BytesTxMulticast += byteCount; + break; + + default: + ASSERT(FALSE); + break; + } + } + else + { + // Transmit error. + Adapter->TransmitFailuresOther += netBufferCount; + } + + currentNbl = nextNbl; + } + + if(DispatchLevel) + { + sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL; + } + + // Complete the NBLs + NdisMSendNetBufferListsComplete( + Adapter->MiniportAdapterHandle, + NetBufferLists, + sendCompleteFlags + ); +} + +BOOLEAN +tapNetBufferListNetBufferLengthsValid( + __in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER_LIST NetBufferLists + ) +/*++ + +Routine Description: + + Scan all NBLs and their linked NBs for valid lengths. + + Fairly absurd to find and packets with bogus lengths, but wise + to check anyway. If ANY packet has a bogus length, then abort the + entire send. + + The only time that one might see this check fail might be during + HCK driver testing. The HKC test might send oversize packets to + determine if the miniport can gracefully deal with them. + + This check is fairly fast. Unlike NDIS 5 packets, fetching NDIS 6 + packets lengths do not require any computation. + +Arguments: + + Adapter Pointer to our adapter context + NetBufferLists Head of a list of NBLs to examine + +Return Value: + + Returns TRUE if all NBs have reasonable lengths. + Otherwise, returns FALSE. + +--*/ +{ + PNET_BUFFER_LIST currentNbl; + + currentNbl = NetBufferLists; + + while (currentNbl) + { + PNET_BUFFER_LIST nextNbl; + PNET_BUFFER currentNb; + + // Locate next NBL + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + + // Locate first NB (aka "packet") + currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl); + + // + // Process all NBs linked to this NBL + // + while(currentNb) + { + PNET_BUFFER nextNb; + ULONG packetLength; + + // Locate next NB + nextNb = NET_BUFFER_NEXT_NB(currentNb); + + packetLength = NET_BUFFER_DATA_LENGTH(currentNb); + + // Minimum packet size is size of Ethernet plus IPv4 headers. + ASSERT(packetLength >= (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)); + + if(packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)) + { + return FALSE; + } + + // Maximum size should be Ethernet header size plus MTU plus modest pad for + // VLAN tag. + ASSERT( packetLength <= (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize)); + + if(packetLength > (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize)) + { + return FALSE; + } + + // Move to next NB + currentNb = nextNb; + } + + // Move to next NBL + currentNbl = nextNbl; + } + + return TRUE; +} + +VOID +AdapterSendNetBufferLists( + __in NDIS_HANDLE MiniportAdapterContext, + __in PNET_BUFFER_LIST NetBufferLists, + __in NDIS_PORT_NUMBER PortNumber, + __in ULONG SendFlags + ) +/*++ + +Routine Description: + + Send Packet Array handler. Called by NDIS whenever a protocol + bound to our miniport sends one or more packets. + + The input packet descriptor pointers have been ordered according + to the order in which the packets should be sent over the network + by the protocol driver that set up the packet array. The NDIS + library preserves the protocol-determined ordering when it submits + each packet array to MiniportSendPackets + + As a deserialized driver, we are responsible for holding incoming send + packets in our internal queue until they can be transmitted over the + network and for preserving the protocol-determined ordering of packet + descriptors incoming to its MiniportSendPackets function. + A deserialized miniport driver must complete each incoming send packet + with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable. + + Runs at IRQL <= DISPATCH_LEVEL + +Arguments: + + MiniportAdapterContext Pointer to our adapter + NetBufferLists Head of a list of NBLs to send + PortNumber A miniport adapter port. Default is 0. + SendFlags Additional flags for the send operation + +Return Value: + + None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS + macro. + +--*/ +{ + NDIS_STATUS status; + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + BOOLEAN DispatchLevel = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL); + PNET_BUFFER_LIST currentNbl; + BOOLEAN validNbLengths; + + UNREFERENCED_PARAMETER(NetBufferLists); + UNREFERENCED_PARAMETER(PortNumber); + UNREFERENCED_PARAMETER(SendFlags); + + ASSERT(PortNumber == 0); // Only the default port is supported + + // + // Can't process sends if TAP device is not open. + // ---------------------------------------------- + // Just perform a "lying send" and return packets as if they + // were successfully sent. + // + if(adapter->TapFileObject == NULL) + { + // + // Complete all NBLs and return if adapter not ready. + // + tapSendNetBufferListsComplete( + adapter, + NetBufferLists, + NDIS_STATUS_SUCCESS, + DispatchLevel + ); + + return; + } + + // + // Check Adapter send/receive ready state. + // + status = tapAdapterSendAndReceiveReady(adapter); + + if(status != NDIS_STATUS_SUCCESS) + { + // + // Complete all NBLs and return if adapter not ready. + // + tapSendNetBufferListsComplete( + adapter, + NetBufferLists, + status, + DispatchLevel + ); + + return; + } + + // + // Scan all NBLs and linked packets for valid lengths. + // --------------------------------------------------- + // If _ANY_ NB length is invalid, then fail the entire send operation. + // + // BUGBUG!!! Perhaps this should be less agressive. Fail only individual + // NBLs... + // + // If length check is valid, then TAP_PACKETS can be safely allocated + // and processed for all NBs being sent. + // + validNbLengths = tapNetBufferListNetBufferLengthsValid( + adapter, + NetBufferLists + ); + + if(!validNbLengths) + { + // + // Complete all NBLs and return if and NB length is invalid. + // + tapSendNetBufferListsComplete( + adapter, + NetBufferLists, + NDIS_STATUS_INVALID_LENGTH, + DispatchLevel + ); + + return; + } + + // + // Process each NBL individually + // + currentNbl = NetBufferLists; + + while (currentNbl) + { + PNET_BUFFER_LIST nextNbl; + PNET_BUFFER currentNb; + + // Locate next NBL + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + + // Locate first NB (aka "packet") + currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl); + + // Transmit all NBs linked to this NBL + while(currentNb) + { + PNET_BUFFER nextNb; + + // Locate next NB + nextNb = NET_BUFFER_NEXT_NB(currentNb); + + // Transmit the NB + tapAdapterTransmit(adapter,currentNb,DispatchLevel); + + // Move to next NB + currentNb = nextNb; + } + + // Move to next NBL + currentNbl = nextNbl; + } + + // Complete all NBLs + tapSendNetBufferListsComplete( + adapter, + NetBufferLists, + NDIS_STATUS_SUCCESS, + DispatchLevel + ); + + // Attempt to complete pending read IRPs from pending TAP + // send packet queue. + tapProcessSendPacketQueue(adapter); +} + +VOID +AdapterCancelSend( + __in NDIS_HANDLE MiniportAdapterContext, + __in PVOID CancelId + ) +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext; + + // + // This miniport completes its sends quickly, so it isn't strictly + // neccessary to implement MiniportCancelSend. + // + // If we did implement it, we'd have to walk the Adapter->SendWaitList + // and look for any NB that points to a NBL where the CancelId matches + // NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(Nbl). For any NB that so matches, + // we'd remove the NB from the SendWaitList and set the NBL's status to + // NDIS_STATUS_SEND_ABORTED, then complete the NBL. + // +} + +// IRP_MJ_READ callback. +NTSTATUS +TapDeviceRead( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +{ + NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success + PIO_STACK_LOCATION irpSp;// Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation( Irp ); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext; + + ASSERT(adapter); + + // + // Sanity checks on state variables + // + if (!tapAdapterReadAndWriteReady(adapter)) + { + //DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n", + // MINIPORT_INSTANCE_ID (adapter))); + //NOTE_ERROR(); + + Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // Save IRP-accessible copy of buffer length + Irp->IoStatus.Information = irpSp->Parameters.Read.Length; + + if (Irp->MdlAddress == NULL) + { + DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n", + MINIPORT_INSTANCE_ID (adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + if ((Irp->AssociatedIrp.SystemBuffer + = MmGetSystemAddressForMdlSafe( + Irp->MdlAddress, + NormalPagePriority + ) ) == NULL + ) + { + DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n", + MINIPORT_INSTANCE_ID (adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // BUGBUG!!! Use RemoveLock??? + + // + // Queue the IRP and return STATUS_PENDING. + // ---------------------------------------- + // Note: IoCsqInsertIrp marks the IRP pending. + // + + // BUGBUG!!! NDIS 5 implementation has IRP_QUEUE_SIZE of 16 and + // does not queue IRP if this capacity is exceeded. + // + // Is this needed??? + // + IoCsqInsertIrp(&adapter->PendingReadIrpQueue.CsqQueue, Irp, NULL); + + // Attempt to complete pending read IRPs from pending TAP + // send packet queue. + tapProcessSendPacketQueue(adapter); + + ntStatus = STATUS_PENDING; + + return ntStatus; +} + diff --git a/windows/TapDriver6/types.h b/windows/TapDriver6/types.h new file mode 100644 index 00000000..acea175c --- /dev/null +++ b/windows/TapDriver6/types.h @@ -0,0 +1,90 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TAP_TYPES_DEFINED +#define TAP_TYPES_DEFINED + +//typedef +//struct _Queue +//{ +// ULONG base; +// ULONG size; +// ULONG capacity; +// ULONG max_size; +// PVOID data[]; +//} Queue; + +//typedef struct _TAP_PACKET; + +//typedef struct _TapExtension +//{ +// // TAP device object and packet queues +// Queue *m_PacketQueue, *m_IrpQueue; +// PDEVICE_OBJECT m_TapDevice; +// NDIS_HANDLE m_TapDeviceHandle; +// ULONG TapFileIsOpen; +// +// // Used to lock packet queues +// NDIS_SPIN_LOCK m_QueueLock; +// BOOLEAN m_AllocatedSpinlocks; +// +// // Used to bracket open/close +// // state changes. +// MUTEX m_OpenCloseMutex; +// +// // True if device has been permanently halted +// BOOLEAN m_Halt; +// +// // TAP device name +// unsigned char *m_TapName; +// UNICODE_STRING m_UnicodeLinkName; +// BOOLEAN m_CreatedUnicodeLinkName; +// +// // Used for device status ioctl only +// const char *m_LastErrorFilename; +// int m_LastErrorLineNumber; +// LONG TapFileOpenCount; +// +// // Flags +// BOOLEAN TapDeviceCreated; +// BOOLEAN m_CalledTapDeviceFreeResources; +// +// // DPC queue for deferred packet injection +// BOOLEAN m_InjectDpcInitialized; +// KDPC m_InjectDpc; +// NDIS_SPIN_LOCK m_InjectLock; +// Queue *m_InjectQueue; +//} +//TapExtension, *TapExtensionPointer; + +typedef struct _InjectPacket + { +# define INJECT_PACKET_SIZE(data_size) (sizeof (InjectPacket) + (data_size)) +# define INJECT_PACKET_FREE(ib) NdisFreeMemory ((ib), INJECT_PACKET_SIZE ((ib)->m_Size), 0) + ULONG m_Size; + UCHAR m_Data []; // m_Data must be the last struct member + } +InjectPacket, *InjectPacketPointer; + +#endif diff --git a/windows/TapDriver6/zttap300.inf b/windows/TapDriver6/zttap300.inf new file mode 100644 index 00000000..f901b130 --- /dev/null +++ b/windows/TapDriver6/zttap300.inf @@ -0,0 +1,143 @@ +; +; ZeroTier One Virtual Network Port NDIS6 Driver +; +; Based on the OpenVPN tap-windows6 driver version 9.21.1 git +; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3. +; See: https://github.com/OpenVPN/tap-windows6 +; +; Modified by ZeroTier, Inc. - https://www.zerotier.com/ +; +; (1) Comment out 'tun' functionality and related features such as DHCP +; emulation, since we don't use any of that. Just want straight 'tap'. +; (2) Added custom IOCTL to enumerate L2 multicast memberships. +; (3) Increase maximum number of multicast memberships to 128. +; (4) Set default and max device MTU to 2800. +; (5) Rename/rebrand driver as ZeroTier network port driver. +; +; Original copyright below. Modifications released under GPLv2 as well. +; +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** +; + +[Version] +Signature = "$Windows NT$" +CatalogFile = zttap300.cat +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %Provider% +Class = Net +DriverVer=04/25/2015,3.00.00.0 + +[Strings] +DeviceDescription = "ZeroTier One Virtual Port" +Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. + +; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! +[Manufacturer] +%Provider%=zttap300,NTamd64 + +[zttap300] +%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated +%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy + +[zttap300.NTamd64] +%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated +%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy + +;----------------- Characteristics ------------ +; NCF_PHYSICAL = 0x04 +; NCF_VIRTUAL = 0x01 +; NCF_SOFTWARE_ENUMERATED = 0x02 +; NCF_HIDDEN = 0x08 +; NCF_NO_SERVICE = 0x10 +; NCF_HAS_UI = 0x80 +;----------------- Characteristics ------------ +[zttap300.ndi] +CopyFiles = zttap300.driver, zttap300.files +AddReg = zttap300.reg +AddReg = zttap300.params.reg +Characteristics = 0x81 +*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD +*MediaType = 0x0 ; NdisMedium802_3 +*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[zttap300.ndi.Services] +AddService = zttap300, 2, zttap300.service + +[zttap300.reg] +HKR, Ndi, Service, 0, "zttap300" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows. +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" +HKR, , Manufacturer, 0, "%Provider%" +HKR, , ProductName, 0, "%DeviceDescription%" + +[zttap300.params.reg] +HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" +HKR, Ndi\params\MTU, Type, 0, "int" +HKR, Ndi\params\MTU, Default, 0, "2800" +HKR, Ndi\params\MTU, Optional, 0, "0" +HKR, Ndi\params\MTU, Min, 0, "100" +HKR, Ndi\params\MTU, Max, 0, "2800" +HKR, Ndi\params\MTU, Step, 0, "1" +HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" +HKR, Ndi\params\MediaStatus, Type, 0, "enum" +HKR, Ndi\params\MediaStatus, Default, 0, "0" +HKR, Ndi\params\MediaStatus, Optional, 0, "0" +HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" +HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" +HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" +HKR, Ndi\params\MAC, Type, 0, "edit" +HKR, Ndi\params\MAC, Optional, 0, "1" +HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" +HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" +HKR, Ndi\params\AllowNonAdmin, Default, 0, "0" +HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" +HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" +HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" + +;---------- Service Type ------------- +; SERVICE_KERNEL_DRIVER = 0x01 +; SERVICE_WIN32_OWN_PROCESS = 0x10 +;---------- Service Type ------------- + +;---------- Start Mode --------------- +; SERVICE_BOOT_START = 0x0 +; SERVICE_SYSTEM_START = 0x1 +; SERVICE_AUTO_START = 0x2 +; SERVICE_DEMAND_START = 0x3 +; SERVICE_DISABLED = 0x4 +;---------- Start Mode --------------- + +[zttap300.service] +DisplayName = %DeviceDescription% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +LoadOrderGroup = NDIS +ServiceBinary = %12%\zttap300.sys + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +[SourceDisksNames] +1 = %DeviceDescription%, zttap300.sys + +[SourceDisksFiles] +zttap300.sys = 1 + +[DestinationDirs] +zttap300.files = 11 +zttap300.driver = 12 + +[zttap300.files] +; + +[zttap300.driver] +zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + diff --git a/windows/ZeroTierOne.sln b/windows/ZeroTierOne.sln index 09a0874b..3aebacb5 100644 --- a/windows/ZeroTierOne.sln +++ b/windows/ZeroTierOne.sln @@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver", "TapDriver\TapD EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroTierOne", "ZeroTierOne\ZeroTierOne.vcxproj", "{B00A4957-5977-4AC1-9EF4-571DC27EADA2}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver6", "TapDriver6\TapDriver6.vcxproj", "{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CD_ROM|Any CPU = CD_ROM|Any CPU @@ -295,6 +297,149 @@ Global {B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.ActiveCfg = Release|Win32 {B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.Build.0 = Release|Win32 {B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.Deploy.0 = Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Any CPU.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.ActiveCfg = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.Build.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.Deploy.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Any CPU.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.Build.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.Deploy.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.Build.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.Deploy.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.ActiveCfg = Win7 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.Build.0 = Win7 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.Deploy.0 = Win7 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.Build.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.Deploy.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Any CPU.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.ActiveCfg = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.Build.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.Deploy.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Any CPU.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.ActiveCfg = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.Build.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.Deploy.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Any CPU.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.ActiveCfg = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.Build.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.Deploy.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Any CPU.ActiveCfg = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.ActiveCfg = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.Build.0 = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.Deploy.0 = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.ActiveCfg = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.Build.0 = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.Deploy.0 = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.ActiveCfg = Vista Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.Build.0 = Vista Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.Deploy.0 = Vista Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.ActiveCfg = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.Build.0 = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.Deploy.0 = Vista Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Any CPU.ActiveCfg = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.ActiveCfg = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.Build.0 = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.Deploy.0 = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.ActiveCfg = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.Build.0 = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.Deploy.0 = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.ActiveCfg = Vista Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.Build.0 = Vista Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.Deploy.0 = Vista Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.ActiveCfg = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.Build.0 = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.Deploy.0 = Vista Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.Build.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.Deploy.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.Build.0 = Win7 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.Deploy.0 = Win7 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.Build.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.Deploy.0 = Win7 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.ActiveCfg = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.Build.0 = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.Deploy.0 = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.ActiveCfg = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.Build.0 = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.Deploy.0 = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.ActiveCfg = Win7 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.Build.0 = Win7 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.Deploy.0 = Win7 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.ActiveCfg = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.Build.0 = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.Deploy.0 = Win7 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Any CPU.ActiveCfg = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.ActiveCfg = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.Build.0 = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.Deploy.0 = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.Build.0 = Win8 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.ActiveCfg = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.Build.0 = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.Deploy.0 = Win8 Debug|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Any CPU.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.ActiveCfg = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.Build.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.Deploy.0 = Win8 Release|x64 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.ActiveCfg = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Build.0 = Win8 Release|Win32 + {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Deploy.0 = Win8 Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |