windows-nt/Source/XPSP1/NT/base/cluster/clusrtl/netcfg.c

1574 lines
42 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
netcfg.c
Abstract:
System network configuration grovelling routines
Author:
Mike Massa (mikemas) May 19, 1997
Revision History:
Who When What
-------- -------- ----------------------------------------------
mikemas 05-19-97 created
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winsock2.h>
#include <cluster.h>
#include <objbase.h>
#include <devguid.h>
#include <netcon.h>
#include <regstr.h>
#include <iphlpapi.h>
//
// Private Constants
//
#define TCPIP_INTERFACES_KEY L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
#define STRING_ARRAY_DELIMITERS " \t,;"
//
// Allocing and cloning helper functions
//
#define AllocGracefully(status, result, len, name) \
result = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, len); \
if (!result) { \
status = GetLastError(); \
ClRtlLogPrint(LOG_CRITICAL, \
"[ClNet] alloc of %1!hs! (%2!d! bytes) failed, status %3!d!\n", \
name,len,status); \
goto exit_gracefully; \
} else { \
status = ERROR_SUCCESS; \
}
#define CloneAnsiString(Status,AnsiStr,WideResult) { \
SIZE_T len = _mbstrlen(AnsiStr) + 1; \
AllocGracefully(status, WideResult, len * sizeof(WCHAR), # AnsiStr); \
mbstowcs(WideResult, AnsiStr, len); \
}
#define CloneWideString(Status,WideStr,WideResult) { \
SIZE_T _size = (wcslen(WideStr) + 1) * sizeof(WCHAR); \
AllocGracefully(Status, WideResult, _size * sizeof(WCHAR), # WideStr); \
memcpy(WideResult, WideStr, _size); \
}
VOID
ClRtlpDeleteInterfaceInfo(
PCLRTL_NET_INTERFACE_INFO InterfaceInfo
)
{
if (InterfaceInfo) {
LocalFree(InterfaceInfo->InterfaceAddressString);
LocalFree(InterfaceInfo->NetworkAddressString);
LocalFree(InterfaceInfo->NetworkMaskString);
LocalFree(InterfaceInfo);
}
} // DeleteInterfaceInfo
PCLRTL_NET_INTERFACE_INFO
ClRtlpCreateInterfaceInfo(
IN CONST PIP_ADDR_STRING IpAddr
)
{
DWORD status;
PCLRTL_NET_INTERFACE_INFO This = 0;
ULONG Addr, Mask, Network;
Addr = inet_addr(IpAddr->IpAddress.String);
Mask = inet_addr(IpAddr->IpMask.String);
Network = Addr & Mask;
if ( (INADDR_NONE == Addr) ||
(INADDR_NONE == Mask) ||
((0 == Network) && Addr && Mask)
)
{
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] Bad ip addr/mask: %1!X! %2!X! %3!X!\n",
Addr,
Mask,
Network
);
status = ERROR_INVALID_PARAMETER;
goto exit_gracefully;
}
AllocGracefully(
status,
This,
sizeof(CLRTL_NET_INTERFACE_INFO),
"CLRTL_NET_INTERFACE_INFO"
);
This->Context = IpAddr -> Context;
This->InterfaceAddress = Addr;
This->NetworkMask = Mask;
This->NetworkAddress = Network;
CloneAnsiString(
status,
IpAddr->IpAddress.String,
This->InterfaceAddressString
);
CloneAnsiString(
status,
IpAddr->IpMask.String,
This->NetworkMaskString
);
status = ClRtlTcpipAddressToString(
Network,
&(This->NetworkAddressString)
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] ClRtlTcpipAddressToString of %1!X! failed, "
"status %2!d!\n",
Network,
status
);
goto exit_gracefully;
}
exit_gracefully:
if (status != ERROR_SUCCESS) {
SetLastError(status);
if (This) {
ClRtlpDeleteInterfaceInfo(This);
This = 0;
}
}
return This;
} // CreateInterfaceInfo
VOID
ClRtlpDeleteAdapter(
PCLRTL_NET_ADAPTER_INFO adapterInfo
)
{
if (adapterInfo) {
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
interfaceInfo = adapterInfo->InterfaceList;
while (interfaceInfo != NULL) {
PCLRTL_NET_INTERFACE_INFO next = interfaceInfo->Next;
ClRtlpDeleteInterfaceInfo(interfaceInfo);
interfaceInfo = next;
}
LocalFree(adapterInfo->DeviceGuid);
LocalFree(adapterInfo->ConnectoidName);
LocalFree(adapterInfo->DeviceName);
LocalFree(adapterInfo->AdapterDomainName);
LocalFree(adapterInfo->DnsServerList);
LocalFree(adapterInfo);
return;
}
} // DeleteAdapter
DWORD
ClRtlpCreateAdapter(
IN PIP_ADAPTER_INFO AdapterInfo,
OUT PCLRTL_NET_ADAPTER_INFO * ppAdapter)
{
DWORD status;
PCLRTL_NET_ADAPTER_INFO adapter = 0;
*ppAdapter = 0;
AllocGracefully(status, adapter, sizeof(*adapter), "NET_ADAPTER_INFO");
ZeroMemory(adapter, sizeof(*adapter));
//
// Assumption here is that:
//
// AdapterName contains Guid in the form {4082164E-A4B5-11D2-89C3-E37CB6BB13FC}
// We need to store it without curly brackets
//
{
SIZE_T len = _mbstrlen(AdapterInfo->AdapterName); // not including 0, but including { and } //
AllocGracefully(status, adapter->DeviceGuid,
sizeof(WCHAR) * (len - 1), "adapter->DeviceGuid");
mbstowcs(adapter->DeviceGuid, AdapterInfo->AdapterName+1, len-1);
adapter->DeviceGuid[len - 2] = UNICODE_NULL;
}
adapter->Index = AdapterInfo->Index;
{
PIP_ADDR_STRING IpAddr = &AdapterInfo->IpAddressList;
while ( IpAddr ) {
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
interfaceInfo = ClRtlpCreateInterfaceInfo(IpAddr);
if (!interfaceInfo) {
// CreateInterfaceInfo logs the error message //
// clean up will be done by DeleteAdapter //
status = GetLastError();
goto exit_gracefully;
}
interfaceInfo->Next = adapter->InterfaceList;
adapter->InterfaceList = interfaceInfo;
++(adapter->InterfaceCount);
IpAddr = IpAddr -> Next;
}
if (adapter->InterfaceList) {
adapter->InterfaceList->Flags |= CLRTL_NET_INTERFACE_PRIMARY;
}
}
exit_gracefully:
if (status != ERROR_SUCCESS) {
ClRtlpDeleteAdapter(adapter);
} else {
*ppAdapter = adapter;
}
return status;
} // CreateAdapter
PCLRTL_NET_ADAPTER_ENUM
ClRtlpCreateAdapterEnum()
{
DWORD status;
DWORD len;
PIP_ADAPTER_INFO SingleAdapter = 0;
PIP_ADAPTER_INFO AdapterInfo = 0;
PCLRTL_NET_ADAPTER_ENUM AdapterEnum = 0;
len = 0;
for(;;) {
status = GetAdaptersInfo(AdapterInfo, &len);
if (status == ERROR_SUCCESS) {
break;
}
if (status != ERROR_BUFFER_OVERFLOW) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] GetAdaptersInfo returned %1!d!\n", status);
goto exit_gracefully;
}
LocalFree(AdapterInfo); // LocalFree(0) is OK //
AllocGracefully(status, AdapterInfo, len, "IP_ADAPTER_INFO");
}
AllocGracefully(status, AdapterEnum,
sizeof(*AdapterEnum), "PCLRTL_NET_ADAPTER_ENUM");
ZeroMemory(AdapterEnum, sizeof(*AdapterEnum));
SingleAdapter = AdapterInfo;
while (SingleAdapter) {
if (SingleAdapter->Type != MIB_IF_TYPE_LOOPBACK &&
SingleAdapter->Type != MIB_IF_TYPE_PPP &&
SingleAdapter->Type != MIB_IF_TYPE_SLIP )
{
PCLRTL_NET_ADAPTER_INFO Adapter = 0;
status = ClRtlpCreateAdapter(SingleAdapter, &Adapter);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] CreateAdapter %1!d! failed, status %2!d!\n",
AdapterEnum->AdapterCount, status);
goto exit_gracefully;
}
//
// Push the adapter into Enumeration List
//
Adapter->Next = AdapterEnum->AdapterList;
AdapterEnum->AdapterList = Adapter;
++(AdapterEnum->AdapterCount);
}
SingleAdapter = SingleAdapter->Next;
}
exit_gracefully:
if (status != ERROR_SUCCESS) {
SetLastError(status);
ClRtlFreeNetAdapterEnum(AdapterEnum);
AdapterEnum = 0;
}
LocalFree(AdapterInfo);
return AdapterEnum;
} // CreateAdapterEnum
HKEY
ClRtlpFindAdapterKey(
HKEY TcpInterfacesKey,
LPWSTR AdapterGuidString
)
/*++
Routine Description:
Given the adapter GUID, look through the key names under
TCP's Interfaces key and see if a match can be found. The
key names should have the GUID as some part of the name.
Arguments:
TcpInterfacesKey - handle to TCP's interfaces area
AdapterGuidString - pointer to string representing adapter's GUID
Return Value:
Handle to the interface key; otherwise NULL
--*/
{
HKEY AdapterInterfaceKey = NULL;
WCHAR KeyName[REGSTR_MAX_VALUE_LENGTH + 1];
DWORD KeyLength = sizeof( KeyName )/sizeof(TCHAR);
DWORD index = 0;
BOOL FoundMatch = FALSE;
size_t SubStringPos;
DWORD Status;
FILETIME FileTime;
//
// enum the key names under the interfaces
//
do {
Status = RegEnumKeyEx(TcpInterfacesKey,
index,
KeyName,
&KeyLength,
NULL,
NULL,
NULL,
&FileTime);
if ( Status != ERROR_SUCCESS ) {
break;
}
//
// find the beginning of the match
//
_wcsupr( KeyName );
if (wcsstr( KeyName, AdapterGuidString )) {
FoundMatch = TRUE;
break;
}
++index;
KeyLength = sizeof( KeyName );
} while ( TRUE );
if ( FoundMatch ) {
Status = RegOpenKeyW(TcpInterfacesKey,
KeyName,
&AdapterInterfaceKey);
if ( Status != ERROR_SUCCESS ) {
AdapterInterfaceKey = NULL;
}
}
return AdapterInterfaceKey;
} // FindAdapterKey
DWORD
ClRtlpConvertIPAddressString(
LPSTR DnsServerString,
PDWORD ServerCount,
PDWORD * ServerList)
/*++
Routine Description:
Convert the string of DNS server addresses to binary
Arguments:
DnsServerString - concat'ed string of IP addresses that can be separated
by white space of commas
ServerCount - pointer to DWORD that receives # of addresses detected
ServerList - pointer to DWORD array of converted IP addresses
Return Value:
ERROR_SUCCESS if everything went ok
--*/
{
#define MAX_DNS_SERVER_ADDRESSES 100
PCHAR stringPointer = DnsServerString;
DWORD stringCount = 0;
PDWORD serverList = NULL;
LPSTR stringAddress[ MAX_DNS_SERVER_ADDRESSES ];
//
// count how many addresses are in the string and null terminate them for
// inet_addr
//
stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS);
stringAddress[0] = stringPointer;
stringCount = 1;
while (stringCount < MAX_DNS_SERVER_ADDRESSES &&
(stringPointer = strpbrk(stringPointer, STRING_ARRAY_DELIMITERS)))
{
*stringPointer++ = '\0';
stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS);
stringAddress[stringCount] = stringPointer;
if (*stringPointer) {
++stringCount;
}
}
serverList = LocalAlloc( LMEM_FIXED, stringCount * sizeof( DWORD ));
if ( serverList == NULL ) {
return GetLastError();
}
*ServerCount = stringCount;
*ServerList = serverList;
while ( stringCount-- ) {
serverList[ stringCount ] = inet_addr( stringAddress[ stringCount ]);
}
return ERROR_SUCCESS;
} // ConvertIPAddressString
typedef BOOLEAN (*ENUM_CALLBACK)(NETCON_PROPERTIES *,
INetConnection*,
PVOID Context);
HRESULT
ClRtlpHrEnumConnections(
IN ENUM_CALLBACK enumCallback,
IN PVOID Context
)
/*++
Routine Description:
Enumerate Connection Manager Connections
Arguments:
enumCallback - callback to be called for every connection
Context - to be passed to a callback
Return Value:
S_OK or HRESULT error code
--*/
{
HRESULT hr;
INetConnectionManager * NcManager = NULL;
IEnumNetConnection * EnumNc = NULL;
INetConnection * NetConnection = NULL;
NETCON_PROPERTIES * NcProps = NULL;
DWORD dwNumConnectionsReturned;
LPWSTR deviceGuidString = NULL;
//
// instantiate a connection mgr object and enum the connections
//
hr = CoCreateInstance((REFCLSID)&CLSID_ConnectionManager,
NULL,
CLSCTX_LOCAL_SERVER,
(REFIID)&IID_INetConnectionManager,
&NcManager);
if (FAILED(hr)) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] INetConnectionManager_CoCreateInstance failed, status %1!X!\n",
hr);
goto exit_gracefully;
}
hr = INetConnectionManager_EnumConnections(NcManager,
NCME_DEFAULT,
&EnumNc);
if (FAILED(hr)) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] INetConnectionManager_EnumConnections failed, status %1!X!\n",
hr);
goto exit_gracefully;
}
IEnumNetConnection_Reset( EnumNc );
while (TRUE) {
hr = IEnumNetConnection_Next(EnumNc,
1,
&NetConnection,
&dwNumConnectionsReturned);
if (FAILED(hr)) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] IEnumNetConnection_Next failed, status %1!X!\n",
hr);
goto exit_gracefully;
}
if ( dwNumConnectionsReturned == 0 ) {
hr = S_OK;
break;
}
hr = INetConnection_GetProperties(NetConnection, &NcProps);
if (SUCCEEDED( hr )) {
BOOLEAN bCont;
bCont = enumCallback(NcProps, NetConnection, Context);
NcFreeNetconProperties(NcProps);
NcProps = 0;
if (!bCont) {
break;
}
}
INetConnection_Release( NetConnection ); NetConnection = NULL;
}
exit_gracefully:
if (EnumNc != NULL) {
IEnumNetConnection_Release( EnumNc );
}
if (NcManager != NULL) {
INetConnectionManager_Release( NcManager );
}
return hr;
} // HrEnumConnections
VOID
ClRtlpProcessNetConfigurationAdapter(
HKEY TcpInterfacesKey,
PCLRTL_NET_ADAPTER_ENUM adapterEnum,
NETCON_PROPERTIES * NCProps,
LPWSTR DeviceGuidString
)
/*++
Routine Description:
For a given conn mgr object, determine if it is in use by
TCP. This is acheived by comparing the adapter ID in the tcpip
adapter enumeration with the connection object's guid.
Arguments:
TcpInterfacessKey - handle to the root of the TCP\Parameters\Interfaces area
adapterEnum - pointer to enumeration of adapters and their interfaces
actually in use by TCP
NCProps - Connectoid properties.
DeviceGuidString - Guid for the connectoid (and for the associated adapter).
Return Value:
None
--*/
{
HKEY AdaptersKey;
HKEY DHCPAdaptersKey = NULL;
HKEY InterfacesKey = NULL;
PCLRTL_NET_ADAPTER_INFO adapterInfo = NULL;
DWORD valueSize;
DWORD valueType;
LPWSTR valueName;
LPSTR ansiValueName;
BOOL ignoreAdapter = FALSE;
DWORD NTEContext;
DWORD Status;
BOOL dhcpEnabled;
//
// Get the TCP/IP interfaces registry key for this adapter.
//
InterfacesKey = ClRtlpFindAdapterKey(
TcpInterfacesKey,
DeviceGuidString
);
if (InterfacesKey == NULL) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] No Interfaces key for %1!ws!\n",
DeviceGuidString
);
goto exit_gracefully;
}
//
// see if we should be ignoring this adapter per the registry
//
valueSize = sizeof(DWORD);
Status = RegQueryValueExW(InterfacesKey,
L"MSCSHidden",
NULL,
&valueType,
(LPBYTE) &ignoreAdapter,
&valueSize);
if ( Status != ERROR_SUCCESS ) {
ignoreAdapter = FALSE;
}
//
// Search the enum for this adapter.
//
adapterInfo = ClRtlFindNetAdapterById(adapterEnum, DeviceGuidString);
if (adapterInfo != NULL) {
CloneWideString(Status, NCProps->pszwDeviceName, adapterInfo->DeviceName);
CloneWideString(Status, NCProps->pszwName, adapterInfo->ConnectoidName);
//
// Check if this is a hidden netcard.
//
if ( ignoreAdapter ) {
adapterInfo->Flags |= CLRTL_NET_ADAPTER_HIDDEN;
}
//
// Store the NCStatus in the adapter info structure
//
adapterInfo->NCStatus = NCProps->Status;
//
// get the domain name and DHCP server list (if any) associated
// with this adapter. The Domain value has precedence over
// DhcpDomain. If that value is empty/doesn't exist, then use
// DhcpDomain only if EnableDHCP is set to one.
//
Status = ClRtlRegQueryDword(InterfacesKey,
L"EnableDHCP",
&dhcpEnabled,
NULL);
if ( Status != ERROR_SUCCESS ) {
dhcpEnabled = FALSE;
}
valueName = L"Domain";
valueSize = 0;
Status = RegQueryValueExW(InterfacesKey,
valueName,
NULL,
&valueType,
(LPBYTE)NULL,
&valueSize);
if ( Status != ERROR_SUCCESS || valueSize == sizeof(UNICODE_NULL)) {
//
// it didn't exist or the value was NULL. if were using DHCP,
// then check to see if DHCP supplied domain name was
// specified
//
if ( dhcpEnabled ) {
valueName = L"DhcpDomain";
Status = RegQueryValueExW(InterfacesKey,
valueName,
NULL,
&valueType,
(LPBYTE)NULL,
&valueSize);
} else {
Status = ERROR_FILE_NOT_FOUND;
}
}
if ( Status == ERROR_SUCCESS && valueSize > sizeof(UNICODE_NULL)) {
//
// legit domain name was found (somewhere). store it in the
// adapter info
//
adapterInfo->AdapterDomainName = LocalAlloc(LMEM_FIXED,
valueSize +
sizeof(UNICODE_NULL));
if ( adapterInfo->AdapterDomainName != NULL ) {
Status = RegQueryValueExW(InterfacesKey,
valueName,
NULL,
&valueType,
(LPBYTE)adapterInfo->AdapterDomainName,
&valueSize);
if ( Status != ERROR_SUCCESS ) {
LocalFree( adapterInfo->AdapterDomainName );
adapterInfo->AdapterDomainName = NULL;
}
#if CLUSTER_BETA
else {
ClRtlLogPrint(LOG_NOISE,
" %1!ws! key: %2!ws!\n",
valueName,
adapterInfo->AdapterDomainName);
}
#endif
} else {
Status = GetLastError();
}
}
//
// now get the DNS server list in a similar fashion. The
// NameServer value has precedence over DhcpNameServer but we only
// check the DHCP values if DHCP is enabled (just like
// above). Note that we use the Ansi APIs since we need to convert
// the IP addresses into binary form and there is no wide char
// form of inet_addr.
//
ansiValueName = "NameServer";
valueSize = 0;
Status = RegQueryValueExA(InterfacesKey,
ansiValueName,
NULL,
&valueType,
(LPBYTE)NULL,
&valueSize);
if ( Status != ERROR_SUCCESS || valueSize == 1 ) {
if ( dhcpEnabled ) {
ansiValueName = "DhcpNameServer";
Status = RegQueryValueExA(InterfacesKey,
ansiValueName,
NULL,
&valueType,
(LPBYTE)NULL,
&valueSize);
} else {
Status = ERROR_FILE_NOT_FOUND;
}
}
if ( Status == ERROR_SUCCESS && valueSize > 0 ) {
PCHAR nameServerString;
nameServerString = LocalAlloc( LMEM_FIXED, valueSize + 1 );
if ( nameServerString != NULL ) {
Status = RegQueryValueExA(InterfacesKey,
ansiValueName,
NULL,
&valueType,
(LPBYTE)nameServerString,
&valueSize);
if ( Status == ERROR_SUCCESS ) {
DWORD serverCount;
PDWORD serverList;
#if CLUSTER_BETA
ClRtlLogPrint(LOG_NOISE,
" %1!hs! key: %2!hs!\n",
ansiValueName,
nameServerString);
#endif
Status = ClRtlpConvertIPAddressString(
nameServerString,
&serverCount,
&serverList
);
if ( Status == ERROR_SUCCESS ) {
adapterInfo->DnsServerCount = serverCount;
adapterInfo->DnsServerList = serverList;
} else {
adapterInfo->DnsServerCount = 0;
adapterInfo->DnsServerList = NULL;
}
} else {
adapterInfo->DnsServerCount = 0;
adapterInfo->DnsServerList = NULL;
}
LocalFree( nameServerString );
} else {
Status = GetLastError();
}
}
}
if ( adapterInfo == NULL ) {
//
// TCP/IP is not bound to this adapter right now. PnP?
//
ClRtlLogPrint(LOG_UNUSUAL,
"[ClNet] Tcpip is not bound to adapter %1!ws!.\n",
DeviceGuidString
);
}
exit_gracefully:
if (InterfacesKey != NULL) {
RegCloseKey( InterfacesKey );
}
return;
} // ProcessNetConfigurationAdapter
typedef struct _CONFIGURATION_CONTEXT
{
PCLRTL_NET_ADAPTER_ENUM adapterEnum;
HKEY TcpInterfacesKey;
}
CONFIGURATION_CONTEXT, *PCONFIGURATION_CONTEXT;
typedef WCHAR GUIDSTR[32 * 3];
VOID GuidToStr(LPGUID Guid, PWCHAR buf)
{
//
// GUIDs look like this: 4082164E-A4B5-11D2-89C3-E37CB6BB13FC
//
wsprintfW(
buf,
L"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
Guid->Data1, Guid->Data2, Guid->Data3,
Guid->Data4[0], Guid->Data4[1], Guid->Data4[2], Guid->Data4[3],
Guid->Data4[4], Guid->Data4[5], Guid->Data4[6], Guid->Data4[7]
);
}
BOOLEAN
ClRtlpProcessConfigurationCallback(
NETCON_PROPERTIES * NCProps,
INetConnection * NetConnection,
PVOID Context
)
{
PCONFIGURATION_CONTEXT Ctx =
(PCONFIGURATION_CONTEXT) Context;
if ( NCProps->MediaType == NCM_LAN &&
NCProps->Status != NCS_HARDWARE_NOT_PRESENT &&
NCProps->Status != NCS_HARDWARE_DISABLED &&
NCProps->Status != NCS_HARDWARE_MALFUNCTION)
{
GUIDSTR deviceGuidString;
GuidToStr(&NCProps->guidId, deviceGuidString);
ClRtlpProcessNetConfigurationAdapter(
Ctx->TcpInterfacesKey,
Ctx->adapterEnum,
NCProps,
deviceGuidString
);
//
// the strings in the properties struct are either kept or
// or freed in ProcessNetConfigurationAdapter. If they are
// used, then they are freed when the adapter enum is freed
//
}
return TRUE;
} // ProcessConfigurationCallback
PCLRTL_NET_ADAPTER_ENUM
ClRtlEnumNetAdapters(
VOID
)
/*++
Routine Description:
Enumerates all of the installed network adapters to which TCP/IP
is bound.
Arguments:
None.
Return Value:
A pointer to a network adapter enumeration, if successful.
NULL if unsuccessful. Extended error information is available from
GetLastError().
--*/
{
DWORD status;
PCLRTL_NET_ADAPTER_INFO adapterInfo = NULL;
CONFIGURATION_CONTEXT Ctx;
PVOID wTimer;
ZeroMemory(&Ctx, sizeof(Ctx));
//
// First get the list of bound adapters & interfaces from the
// tcpip stack.
//
Ctx.adapterEnum = ClRtlpCreateAdapterEnum();
if (Ctx.adapterEnum == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] GetTcpipAdaptersAndInterfaces failed %1!u!\n", status);
SetLastError(status);
return(NULL);
}
//
// Open the Services portion of the registry
//
status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
TCPIP_INTERFACES_KEY,
&Ctx.TcpInterfacesKey);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] Open of TCP Params key failed - %1!u!\n",
status
);
goto exit_gracefully;
}
// This function might hang, so setting the watchdog timer to 2 mins (2 * 60 * 1000) ms
wTimer = ClRtlSetWatchdogTimer(120000, L"Calling EnumConnections");
status = ClRtlpHrEnumConnections(
ClRtlpProcessConfigurationCallback,
&Ctx
);
ClRtlCancelWatchdogTimer(wTimer);
if (status != S_OK) {
goto exit_gracefully;
}
//
// Finally, ensure that we found a name for each adapter in the enum.
//
for (adapterInfo = Ctx.adapterEnum->AdapterList;
adapterInfo != NULL;
adapterInfo = adapterInfo->Next
)
{
if (adapterInfo->ConnectoidName == NULL) {
if ( adapterInfo->InterfaceCount > 0 ) {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] No installed adapter was found for IP address %1!ws!\n",
adapterInfo->InterfaceList->InterfaceAddressString
);
} else {
ClRtlLogPrint(LOG_CRITICAL,
"[ClNet] No installed adapter was found for Tcpip IF entity %1!u!\n",
adapterInfo->Index
);
}
status = ERROR_FILE_NOT_FOUND;
goto exit_gracefully;
}
}
#if CLUSTER_BETA
ClRtlLogPrint(LOG_NOISE,
"[ClNet] Successfully enumerated all adapters and interfaces\n");
#endif
status = ERROR_SUCCESS;
exit_gracefully:
if (Ctx.TcpInterfacesKey != NULL) {
RegCloseKey(Ctx.TcpInterfacesKey);
}
if (status != ERROR_SUCCESS) {
if (Ctx.adapterEnum != NULL) {
ClRtlFreeNetAdapterEnum(Ctx.adapterEnum);
Ctx.adapterEnum = NULL;
}
SetLastError(status);
}
return(Ctx.adapterEnum);
} // ClRtlEnumNetAdapters
VOID
ClRtlFreeNetAdapterEnum(
IN PCLRTL_NET_ADAPTER_ENUM AdapterEnum
)
/*++
Routine Description:
Frees a network adapter enumeration structure.
Arguments:
AdapterEnum - A pointer to the structure to be freed.
Return Value:
None.
--*/
{
if (AdapterEnum) {
PCLRTL_NET_ADAPTER_INFO p = AdapterEnum -> AdapterList;
while (p) {
PCLRTL_NET_ADAPTER_INFO next = p->Next;
ClRtlpDeleteAdapter(p);
p = next;
}
LocalFree(AdapterEnum);
}
} // ClRtlFreeNetAdapterEnum
PCLRTL_NET_ADAPTER_INFO
ClRtlFindNetAdapterById(
PCLRTL_NET_ADAPTER_ENUM AdapterEnum,
LPWSTR AdapterId
)
{
PCLRTL_NET_ADAPTER_INFO adapterInfo;
for ( adapterInfo = AdapterEnum->AdapterList;
adapterInfo != NULL;
adapterInfo = adapterInfo->Next
)
{
if (wcscmp(AdapterId, adapterInfo->DeviceGuid) == 0) {
if (!adapterInfo->Ignore) {
return(adapterInfo);
}
else {
return(NULL);
}
}
}
return(NULL);
} // ClRtlFindNetAdapterById
PCLRTL_NET_INTERFACE_INFO
ClRtlFindNetInterfaceByNetworkAddress(
IN PCLRTL_NET_ADAPTER_INFO AdapterInfo,
IN LPWSTR NetworkAddress
)
{
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
for (interfaceInfo = AdapterInfo->InterfaceList;
interfaceInfo != NULL;
interfaceInfo = interfaceInfo->Next
)
{
if (interfaceInfo->Ignore == FALSE) {
//
// We only look at the primary interface on the
// adapter right now.
//
if (interfaceInfo->Flags & CLRTL_NET_INTERFACE_PRIMARY)
{
if ( wcscmp(
interfaceInfo->NetworkAddressString,
NetworkAddress
) == 0 )
{
return(interfaceInfo);
}
}
}
}
return(NULL);
} // ClRtlFindNetInterfaceByNetworkAddress
PCLRTL_NET_ADAPTER_INFO
ClRtlFindNetAdapterByNetworkAddress(
IN PCLRTL_NET_ADAPTER_ENUM AdapterEnum,
IN LPWSTR NetworkAddress,
OUT PCLRTL_NET_INTERFACE_INFO * InterfaceInfo
)
{
PCLRTL_NET_ADAPTER_INFO adapterInfo;
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
for ( adapterInfo = AdapterEnum->AdapterList;
adapterInfo != NULL;
adapterInfo = adapterInfo->Next
)
{
if (adapterInfo->Ignore == FALSE) {
for (interfaceInfo = adapterInfo->InterfaceList;
interfaceInfo != NULL;
interfaceInfo = interfaceInfo->Next
)
{
if (interfaceInfo->Ignore == FALSE) {
//
// We only look at the primary interface on the
// adapter right now.
//
if (interfaceInfo->Flags & CLRTL_NET_INTERFACE_PRIMARY) {
if ( wcscmp(
interfaceInfo->NetworkAddressString,
NetworkAddress
) == 0 )
{
*InterfaceInfo = interfaceInfo;
return(adapterInfo);
}
}
}
}
}
}
*InterfaceInfo = NULL;
return(NULL);
} // ClRtlFindNetAdapterByNetworkAddress
PCLRTL_NET_ADAPTER_INFO
ClRtlFindNetAdapterByInterfaceAddress(
IN PCLRTL_NET_ADAPTER_ENUM AdapterEnum,
IN LPWSTR InterfaceAddressString,
OUT PCLRTL_NET_INTERFACE_INFO * InterfaceInfo
)
/*++
For a given IP interface address, find the
adapter that is hosting that address.
--*/
{
PCLRTL_NET_ADAPTER_INFO adapterInfo;
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
for ( adapterInfo = AdapterEnum->AdapterList;
adapterInfo != NULL;
adapterInfo = adapterInfo->Next
)
{
if (adapterInfo->Ignore == FALSE) {
for (interfaceInfo = adapterInfo->InterfaceList;
interfaceInfo != NULL;
interfaceInfo = interfaceInfo->Next
)
{
if (interfaceInfo->Ignore == FALSE ) {
if ( wcscmp( interfaceInfo->InterfaceAddressString,
InterfaceAddressString ) == 0 ) {
*InterfaceInfo = interfaceInfo;
return(adapterInfo);
}
}
}
}
}
*InterfaceInfo = NULL;
return(NULL);
} // ClRtlFindNetAdapterByInterfaceAddress
PCLRTL_NET_INTERFACE_INFO
ClRtlGetPrimaryNetInterface(
IN PCLRTL_NET_ADAPTER_INFO AdapterInfo
)
{
PCLRTL_NET_INTERFACE_INFO interfaceInfo;
for (interfaceInfo = AdapterInfo->InterfaceList;
interfaceInfo != NULL;
interfaceInfo = interfaceInfo->Next
)
{
if (interfaceInfo->Flags & CLRTL_NET_INTERFACE_PRIMARY) {
if (!interfaceInfo->Ignore) {
return(interfaceInfo);
}
else {
return(NULL);
}
}
}
return(NULL);
} // ClRtlGetPrimaryNetInterface
LPWSTR
ClRtlGetConnectoidName(
INetConnection * NetConnection
)
{
DWORD status;
NETCON_PROPERTIES * NcProps = NULL;
LPWSTR name = NULL;
status = INetConnection_GetProperties(NetConnection, &NcProps);
if (SUCCEEDED( status )) {
DWORD nameLength = (lstrlenW(NcProps->pszwName) * sizeof(WCHAR)) +
sizeof(UNICODE_NULL);
name = LocalAlloc(LMEM_FIXED, nameLength);
if (name != NULL) {
lstrcpyW(name, NcProps->pszwName);
}
else {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
NcFreeNetconProperties( NcProps );
}
else {
SetLastError(status);
}
return(name);
} // ClRtlGetConnectoidName
typedef struct _FIND_CONNECTOID_CONTEXT
{
GUID ConnectoidGuid;
LPCWSTR ConnectoidName;
INetConnection * NetConnection;
}
FIND_CONNECTOID_CONTEXT, *PFIND_CONNECTOID_CONTEXT;
BOOLEAN
ClRtlpFindConnectoidByGuidCallback(
NETCON_PROPERTIES * NcProp,
INetConnection * NetConnection,
PVOID Context
)
{
PFIND_CONNECTOID_CONTEXT Ctx =
(PFIND_CONNECTOID_CONTEXT) Context;
if ( IsEqualGUID(&Ctx->ConnectoidGuid, &NcProp->guidId) ) {
INetConnection_AddRef(NetConnection);
Ctx->NetConnection = NetConnection;
return FALSE;
}
return TRUE;
} // FindConnectoidByGuidCallback
INetConnection *
ClRtlFindConnectoidByGuid(
LPWSTR ConnectoidGuidStr
)
{
FIND_CONNECTOID_CONTEXT Ctx;
HRESULT hr;
RPC_STATUS rpcStatus;
ZeroMemory(&Ctx, sizeof(Ctx));
rpcStatus = UuidFromStringW (
(LPWSTR)ConnectoidGuidStr,
&Ctx.ConnectoidGuid);
if (rpcStatus != ERROR_SUCCESS) {
SetLastError( HRESULT_FROM_WIN32(rpcStatus) );
return 0;
}
hr = ClRtlpHrEnumConnections(ClRtlpFindConnectoidByGuidCallback, &Ctx);
if (hr != S_OK) {
SetLastError(hr);
return 0;
} else {
return Ctx.NetConnection;
}
} // ClRtlFindConnectoidByGuid
BOOLEAN
ClRtlpFindConnectoidByNameCallback(
NETCON_PROPERTIES * NcProp,
INetConnection * NetConnection,
PVOID Context
)
{
PFIND_CONNECTOID_CONTEXT Ctx =
(PFIND_CONNECTOID_CONTEXT) Context;
if ( lstrcmpiW(Ctx->ConnectoidName, NcProp->pszwName) == 0 ) {
INetConnection_AddRef(NetConnection);
Ctx->NetConnection = NetConnection;
return FALSE;
}
return TRUE;
} // FindConnectoidByNameCallback
INetConnection *
ClRtlFindConnectoidByName(
LPCWSTR ConnectoidName
)
{
FIND_CONNECTOID_CONTEXT Ctx;
HRESULT hr;
ZeroMemory(&Ctx, sizeof(Ctx));
Ctx.ConnectoidName = ConnectoidName;
hr = ClRtlpHrEnumConnections(ClRtlpFindConnectoidByNameCallback, &Ctx);
if (hr != S_OK) {
SetLastError(hr);
return 0;
} else {
return Ctx.NetConnection;
}
} // ClRtlFindConnectoidByName
DWORD
ClRtlSetConnectoidName(
INetConnection * NetConnection,
LPWSTR NewConnectoidName
)
/*++
Routine Description:
Set the conn mgr object in the connections folder to the
supplied name. This routine must deal with collisions since
the name change could be the result of a node joining the
cluster whose conn obj name in the connection folder had
changed while the cluster service was stopped on that node.
If a collision is detected, the existing name is changed to
have an "(previous)" appended to it.
Arguments:
NetConnection - Connect object to set.
NewConnectoidName - new name
Return Value:
Win32 error status
--*/
{
DWORD status = E_UNEXPECTED;
INetConnection * connectoidObj;
LPWSTR tempName;
ULONG iteration = 2;
GUIDSTR connectoidGuid;
//
// first see if there is a collision with the new name. If so,
// we'll rename the collided name, since we need to make all
// the cluster connectoids the same.
//
connectoidObj = ClRtlFindConnectoidByName( NewConnectoidName );
if ( connectoidObj != NULL ) {
NETCON_PROPERTIES * NcProps = NULL;
status = INetConnection_GetProperties(connectoidObj, &NcProps);
if (SUCCEEDED( status )) {
GuidToStr(&NcProps->guidId, connectoidGuid);
NcFreeNetconProperties( NcProps );
}
else {
wsprintf(
&(connectoidGuid[0]),
L"????????-????-????-????-??????????????"
);
}
ClRtlLogPrint(LOG_UNUSUAL,
"[ClNet] New connectoid name '%1!ws!' collides with name of "
"existing connectoid (%2!ws!). Renaming existing connectoid.\n",
NewConnectoidName,
connectoidGuid
);
//
// allocate enough space for the connectoid name with a trailing
// "(ddd)". 3 digits for the number should be enough
//
tempName = LocalAlloc(
LMEM_FIXED,
(wcslen( NewConnectoidName ) + 6) * sizeof(WCHAR)
);
if ( tempName == NULL ) {
INetConnection_Release( connectoidObj );
return ERROR_OUTOFMEMORY;
}
do {
wsprintf( tempName, L"%s(%u)", NewConnectoidName, iteration++ );
status = INetConnection_Rename( connectoidObj, tempName );
} while ( !SUCCEEDED( status ) && iteration <= 999 );
if ( iteration > 999 ) {
ClRtlLogPrint(LOG_UNUSUAL,
"[ClNet] Failed to create a unique name for connectoid "
"'%1!ws!' (%2!ws!)\n",
NewConnectoidName,
connectoidGuid
);
INetConnection_Release( connectoidObj );
return(ERROR_DUP_NAME);
}
ClRtlLogPrint(LOG_NOISE,
"[ClNet] Renamed existing connectoid '%1!ws!' (%2!ws!) to '%3!ws!' "
"due to a collision with the name of cluster network.\n",
NewConnectoidName,
connectoidGuid,
tempName
);
INetConnection_Release( connectoidObj );
}
//
// now set the connectoid to the new name
//
status = INetConnection_Rename( NetConnection, NewConnectoidName );
return status;
} // ClRtlSetConnectoidName
DWORD
ClRtlFindConnectoidByNameAndSetName(
LPWSTR ConnectoidName,
LPWSTR NewConnectoidName
)
{
DWORD status = E_UNEXPECTED;
INetConnection * connectoidObj;
connectoidObj = ClRtlFindConnectoidByName( ConnectoidName );
if ( connectoidObj != NULL ) {
status = ClRtlSetConnectoidName(connectoidObj, NewConnectoidName);
INetConnection_Release( connectoidObj );
}
else {
status = GetLastError();
}
return(status);
} // ClRtlFindConnectoidByNameAndSetName
DWORD
ClRtlFindConnectoidByGuidAndSetName(
LPWSTR ConnectoidGuid,
LPWSTR NewConnectoidName
)
{
DWORD status = E_UNEXPECTED;
INetConnection * connectoidObj;
connectoidObj = ClRtlFindConnectoidByGuid( ConnectoidGuid );
if ( connectoidObj != NULL ) {
status = ClRtlSetConnectoidName(connectoidObj, NewConnectoidName);
INetConnection_Release( connectoidObj );
}
else {
status = GetLastError();
}
return(status);
} // ClRtlFindConnectoidByGuidAndSetName