@ -234,10 +234,19 @@ std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf)
return std : : string ( " SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed " ) ;
}
BOOL rebootRequired = FALSE ;
if ( ! WINENV . UpdateDriverForPlugAndPlayDevicesA ( ( HWND ) 0 , WINENV . tapDriverName . c_str ( ) , pathToInf , INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE , & rebootRequired ) ) {
// HACK: During upgrades, this can fail while the installer is still running. So make 60 attempts
// with a 1s delay between each attempt.
bool driverInstalled = false ;
for ( int retryCounter = 0 ; retryCounter < 60 ; + + retryCounter ) {
BOOL rebootRequired = FALSE ;
if ( WINENV . UpdateDriverForPlugAndPlayDevicesA ( ( HWND ) 0 , WINENV . tapDriverName . c_str ( ) , pathToInf , INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE , & rebootRequired ) ) {
driverInstalled = true ;
break ;
} else Sleep ( 1000 ) ;
}
if ( ! driverInstalled ) {
WINENV . SetupDiDestroyDeviceInfoList ( deviceInfoSet ) ;
return std : : string ( " UpdateDriverForPlugAndPlayDevices() failed -- unable to install driver on device " ) ;
return std : : string ( " UpdateDriverForPlugAndPlayDevices() failed (made 60 attempts) " ) ;
}
WINENV . SetupDiDestroyDeviceInfoList ( deviceInfoSet ) ;
@ -285,13 +294,16 @@ std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices()
RegCloseKey ( nwAdapters ) ;
}
std : : string errlist ;
for ( std : : set < std : : string > : : iterator iidp ( instanceIdPathsToRemove . begin ( ) ) ; iidp ! = instanceIdPathsToRemove . end ( ) ; + + iidp ) {
std : : string err = deletePersistentTapDevice ( iidp - > c_str ( ) ) ;
if ( err . length ( ) > 0 )
return err ;
if ( err . length ( ) > 0 ) {
if ( errlist . length ( ) > 0 )
errlist . push_back ( ' , ' ) ;
errlist . append ( err ) ;
}
}
return std : : string ( ) ;
return errlist ;
}
std : : string WindowsEthernetTap : : destroyAllPersistentTapDevices ( )
@ -334,13 +346,16 @@ std::string WindowsEthernetTap::destroyAllPersistentTapDevices()
RegCloseKey ( nwAdapters ) ;
}
std : : string errlist ;
for ( std : : set < std : : string > : : iterator iidp ( instanceIdPathsToRemove . begin ( ) ) ; iidp ! = instanceIdPathsToRemove . end ( ) ; + + iidp ) {
std : : string err = deletePersistentTapDevice ( iidp - > c_str ( ) ) ;
if ( err . length ( ) > 0 )
return err ;
if ( err . length ( ) > 0 ) {
if ( errlist . length ( ) > 0 )
errlist . push_back ( ' , ' ) ;
errlist . append ( err ) ;
}
}
return std : : string ( ) ;
return errlist ;
}
std : : string WindowsEthernetTap : : deletePersistentTapDevice ( const char * instanceId )
@ -455,7 +470,6 @@ WindowsEthernetTap::WindowsEthernetTap(
char subkeyClass [ 4096 ] ;
char data [ 4096 ] ;
char tag [ 24 ] ;
std : : set < std : : string > existingDeviceInstances ;
std : : string mySubkeyName ;
if ( mtu > 2800 )
@ -487,10 +501,8 @@ WindowsEthernetTap::WindowsEthernetTap(
std : : string instanceId ;
type = 0 ;
dataLen = sizeof ( data ) ;
if ( RegGetValueA ( nwAdapters , subkeyName , " NetCfgInstanceId " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) = = ERROR_SUCCESS ) {
if ( RegGetValueA ( nwAdapters , subkeyName , " NetCfgInstanceId " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) = = ERROR_SUCCESS )
instanceId . assign ( data , dataLen ) ;
existingDeviceInstances . insert ( instanceId ) ;
}
std : : string instanceIdPath ;
type = 0 ;
@ -520,50 +532,61 @@ WindowsEthernetTap::WindowsEthernetTap(
// If there is no device, try to create one
bool creatingNewDevice = ( _netCfgInstanceId . length ( ) = = 0 ) ;
if ( creatingNewDevice ) {
std : : string errm = addNewPersistentTapDevice ( ( std : : string ( _pathToHelpers ) + WINENV . tapDriverPath ) . c_str ( ) ) ;
if ( errm . length ( ) ! = 0 )
throw std : : runtime_error ( errm ) ;
// Scan for the new instance by simply looking for taps that weren't originally there...
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 ' ;
for ( int getNewAttemptCounter = 0 ; getNewAttemptCounter < 2 ; + + getNewAttemptCounter ) {
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 ( WINENV . tapDriverName = = data ) {
type = 0 ;
dataLen = sizeof ( data ) ;
if ( RegGetValueA ( nwAdapters , subkeyName , " NetCfgInstanceId " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) = = ERROR_SUCCESS ) {
if ( existingDeviceInstances . count ( std : : string ( data , dataLen ) ) = = 0 ) {
RegSetKeyValueA ( nwAdapters , subkeyName , " _ZeroTierTapIdentifier " , REG_SZ , tag , ( DWORD ) ( strlen ( tag ) + 1 ) ) ;
_netCfgInstanceId . assign ( data , dataLen ) ;
if ( WINENV . tapDriverName = = data ) {
type = 0 ;
dataLen = sizeof ( data ) ;
if ( ( RegGetValueA ( nwAdapters , subkeyName , " _ZeroTierTapIdentifier " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) ! = ERROR_SUCCESS ) | | ( dataLen < = 0 ) ) {
type = 0 ;
dataLen = sizeof ( data ) ;
if ( RegGetValueA ( nwAdapters , subkeyName , " DeviceInstanceID " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) = = ERROR_SUCCESS )
_deviceInstanceId . assign ( data , dataLen ) ;
mySubkeyName = subkeyName ;
if ( RegGetValueA ( nwAdapters , subkeyName , " NetCfgInstanceId " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) = = ERROR_SUCCESS ) {
RegSetKeyValueA ( nwAdapters , subkeyName , " _ZeroTierTapIdentifier " , REG_SZ , tag , ( DWORD ) ( strlen ( tag ) + 1 ) ) ;
// Disable DHCP by default on newly created devices
HKEY tcpIpInterfaces ;
if ( RegOpenKeyExA ( HKEY_LOCAL_MACHINE , " SYSTEM \\ CurrentControlSet \\ services \\ Tcpip \\ Parameters \\ Interfaces " , 0 , KEY_READ | KEY_WRITE , & tcpIpInterfaces ) = = ERROR_SUCCESS ) {
DWORD enable = 0 ;
RegSetKeyValueA ( tcpIpInterfaces , _netCfgInstanceId . c_str ( ) , " EnableDHCP " , REG_DWORD , & enable , sizeof ( enable ) ) ;
RegCloseKey ( tcpIpInterfaces ) ;
}
_netCfgInstanceId . assign ( data , dataLen ) ;
break ; // found it!
type = 0 ;
dataLen = sizeof ( data ) ;
if ( RegGetValueA ( nwAdapters , subkeyName , " DeviceInstanceID " , RRF_RT_ANY , & type , ( PVOID ) data , & dataLen ) = = ERROR_SUCCESS )
_deviceInstanceId . assign ( data , dataLen ) ;
mySubkeyName = subkeyName ;
// Disable DHCP by default on new devices
HKEY tcpIpInterfaces ;
if ( RegOpenKeyExA ( HKEY_LOCAL_MACHINE , " SYSTEM \\ CurrentControlSet \\ services \\ Tcpip \\ Parameters \\ Interfaces " , 0 , KEY_READ | KEY_WRITE , & tcpIpInterfaces ) = = ERROR_SUCCESS ) {
DWORD enable = 0 ;
RegSetKeyValueA ( tcpIpInterfaces , _netCfgInstanceId . c_str ( ) , " EnableDHCP " , REG_DWORD , & enable , sizeof ( enable ) ) ;
RegCloseKey ( tcpIpInterfaces ) ;
}
break ; // found an unused zttap device
}
}
}
}
}
} else break ; // no more keys or error occurred
} else break ; // no more keys or error occurred
}
if ( _netCfgInstanceId . length ( ) > 0 ) {
break ; // found an unused zttap device
} else {
// no unused zttap devices, so create one
std : : string errm = addNewPersistentTapDevice ( ( std : : string ( _pathToHelpers ) + WINENV . tapDriverPath ) . c_str ( ) ) ;
if ( errm . length ( ) > 0 )
throw std : : runtime_error ( std : : string ( " unable to create new device instance: " ) + errm ) ;
}
}
}