Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5253 lines
140 KiB

/*++
Copyright (c) 1992-1999 Microsoft Corporation
Module Name:
ipaddr.c
Abstract:
Resource DLL for an IP address.
Author:
Mike Massa (mikemas) 29-Dec-1995
Revision History:
--*/
#define UNICODE 1
#include "clusres.h"
#include "clusrtl.h"
#include <winsock.h>
#include <ipexport.h>
#include <icmpapi.h>
#include "util.h"
#include "nteapi.h"
#include <dnsapi.h>
//
// Private Constants
//
#define LOG_CURRENT_MODULE LOG_MODULE_IPADDR
#define INVALID_NTE_CONTEXT 0xFFFFFFFF
#define MAX_NODE_ID_LENGTH 5
#define NETINTERFACE_ID_LENGTH 36 // size of a guid
#define NETWORK_ID_LENGTH 36
#define PROP_NAME__NETWORK CLUSREG_NAME_IPADDR_NETWORK
#define PROP_NAME__ADDRESS CLUSREG_NAME_IPADDR_ADDRESS
#define PROP_NAME__SUBNETMASK CLUSREG_NAME_IPADDR_SUBNET_MASK
#define PROP_NAME__ENABLENETBIOS CLUSREG_NAME_IPADDR_ENABLE_NETBIOS
#define PROP_NAME__OVERRIDE_ADDRMATCH CLUSREG_NAME_IPADDR_OVERRIDE_ADDRMATCH
//
// Private Macros
//
#define IpaLogEvent ClusResLogEvent
#define IpaSetResourceStatus ClusResSetResourceStatus
#ifndef ARGUMENT_PRESENT
#define ARGUMENT_PRESENT( ArgumentPointer ) (\
(CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
#endif
#define IpaAcquireGlobalLock() \
{ \
DWORD status; \
status = WaitForSingleObject(IpaGlobalMutex, INFINITE); \
}
#define IpaReleaseGlobalLock() \
{ \
BOOL released; \
released = ReleaseMutex(IpaGlobalMutex); \
}
#define IpaAcquireResourceLock(_res) EnterCriticalSection(&((_res)->Lock))
#define IpaReleaseResourceLock(_res) LeaveCriticalSection(&((_res)->Lock))
#define DBG_PRINT printf
//
// Private Types.
//
typedef struct _IPA_PRIVATE_PROPS {
PWSTR NetworkString;
PWSTR AddressString;
PWSTR SubnetMaskString;
DWORD EnableNetbios;
DWORD OverrideAutomatch;
} IPA_PRIVATE_PROPS, *PIPA_PRIVATE_PROPS;
typedef struct _IPA_LOCAL_PARAMS {
LPWSTR InterfaceId;
LPWSTR InterfaceName;
LPWSTR AdapterName;
LPWSTR AdapterId;
IPAddr NbtPrimaryWinsAddress;
IPAddr NbtSecondaryWinsAddress;
} IPA_LOCAL_PARAMS, *PIPA_LOCAL_PARAMS;
typedef struct {
LIST_ENTRY Linkage;
CLUSTER_RESOURCE_STATE State;
DWORD FailureStatus;
RESOURCE_HANDLE ResourceHandle;
BOOLEAN InternalParametersInitialized;
IPAddr Address;
IPMask SubnetMask;
DWORD EnableNetbios;
IPA_PRIVATE_PROPS InternalPrivateProps;
IPA_LOCAL_PARAMS LocalParams;
HNETINTERFACE InterfaceHandle;
DWORD NteContext;
DWORD NteInstance;
LPWSTR NbtDeviceName;
DWORD NbtDeviceInstance;
CLUS_WORKER OnlineThread;
HKEY ResourceKey;
HKEY ParametersKey;
HKEY NodeParametersKey;
HKEY NetworksKey;
HKEY InterfacesKey;
WCHAR NodeId[MAX_NODE_ID_LENGTH + 1];
CRITICAL_SECTION Lock;
} IPA_RESOURCE, *PIPA_RESOURCE;
//
// Private Data
//
HANDLE IpaGlobalMutex = NULL;
USHORT IpaResourceInstance = 0;
HCLUSTER IpaClusterHandle = NULL;
HCHANGE IpaClusterNotifyHandle = NULL;
HANDLE IpaWorkerThreadHandle = NULL;
DWORD IpaOpenResourceCount = 0;
DWORD IpaOnlineResourceCount = 0;
LIST_ENTRY IpaResourceList = {NULL, NULL};
WCHAR NbtDevicePrefix[] = L"\\Device\\NetBT_Tcpip_{";
WCHAR NbtDeviceSuffix[] = L"}";
DWORD IpaMaxIpAddressStringLength = 0;
RESUTIL_PROPERTY_ITEM
IpaResourcePrivateProperties[] = {
{ PROP_NAME__NETWORK,
NULL,
CLUSPROP_FORMAT_SZ,
0, 0, 0, RESUTIL_PROPITEM_REQUIRED,
FIELD_OFFSET(IPA_PRIVATE_PROPS,NetworkString)
},
{ PROP_NAME__ADDRESS,
NULL,
CLUSPROP_FORMAT_SZ,
0, 0, 0, RESUTIL_PROPITEM_REQUIRED,
FIELD_OFFSET(IPA_PRIVATE_PROPS,AddressString)
},
{ PROP_NAME__SUBNETMASK,
NULL,
CLUSPROP_FORMAT_SZ,
0, 0, 0, RESUTIL_PROPITEM_REQUIRED,
FIELD_OFFSET(IPA_PRIVATE_PROPS,SubnetMaskString)
},
{ PROP_NAME__ENABLENETBIOS,
NULL,
CLUSPROP_FORMAT_DWORD,
1, 0, 0xFFFFFFFF, 0,
FIELD_OFFSET(IPA_PRIVATE_PROPS,EnableNetbios)
},
{ PROP_NAME__OVERRIDE_ADDRMATCH,
NULL,
CLUSPROP_FORMAT_DWORD,
0, 0, 0xFFFFFFFF, 0,
FIELD_OFFSET(IPA_PRIVATE_PROPS,OverrideAutomatch)
},
{ 0 }
};
//
// External Data
//
extern CLRES_FUNCTION_TABLE IpAddrFunctionTable;
//
// Private Routine Headers
//
DWORD
IpaGetPrivateResProperties(
IN OUT PIPA_RESOURCE ResourceEntry,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
);
DWORD
IpaValidatePrivateResProperties(
IN OUT PIPA_RESOURCE ResourceEntry,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PIPA_PRIVATE_PROPS Props
);
DWORD
IpaSetPrivateResProperties(
IN OUT PIPA_RESOURCE ResourceEntry,
IN PVOID InBuffer,
IN DWORD InBufferSize
);
DWORD
IpaWorkerThread(
LPVOID Context
);
VOID
WINAPI
IpaClose(
IN RESID Resource
);
//
// Utility functions
//
BOOLEAN
IpaInit(
VOID
)
/*++
Routine Description:
Process attach initialization routine.
Arguments:
None.
Return Value:
TRUE if initialization succeeded. FALSE otherwise.
--*/
{
INT err;
WSADATA WsaData;
InitializeListHead(&IpaResourceList);
ClRtlQueryTcpipInformation(&IpaMaxIpAddressStringLength, NULL, NULL);
err = WSAStartup(0x0101, &WsaData);
if (err) {
return(FALSE);
}
IpaGlobalMutex = CreateMutex(NULL, FALSE, NULL);
if (IpaGlobalMutex == NULL) {
WSACleanup();
return(FALSE);
}
return(TRUE);
} // IpaInit
VOID
IpaCleanup(
VOID
)
/*++
Routine Description:
Process detach cleanup routine.
Arguments:
None.
Return Value:
None.
--*/
{
if (IpaGlobalMutex != NULL) {
CloseHandle(IpaGlobalMutex);
IpaGlobalMutex = NULL;
}
WSACleanup();
return;
}
LPWSTR
IpaGetNameOfNetwork(
IN OUT PIPA_RESOURCE ResourceEntry,
IN LPCWSTR NetworkId
)
/*++
Routine Description:
Get the name of a network from its GUID.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
NetworkId - Supplies the ID of the network.
Return Value:
String allocated using LocalAlloc() containing the name of the
network.
NULL - An error occurred getting the name of the network. Call
GetLastError() for more details.
--*/
{
DWORD status;
DWORD ival;
DWORD type;
DWORD nameLength;
WCHAR name[256];
LPWSTR networkName = NULL;
HKEY networkKey = NULL;
FILETIME fileTime;
//
// Enumerate the networks, looking for the specified GUID.
//
for ( ival = 0 ; ; ival++ ) {
nameLength = sizeof(name);
status = ClusterRegEnumKey( ResourceEntry->NetworksKey,
ival,
name,
&nameLength,
&fileTime );
if ( status == ERROR_MORE_DATA ) {
continue;
}
if ( status != ERROR_SUCCESS ) {
break;
}
//
// If we found a match, open the key and read the name.
//
if ( lstrcmpiW( name, NetworkId ) == 0 ) {
status = ClusterRegOpenKey( ResourceEntry->NetworksKey,
name,
KEY_READ,
&networkKey );
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
//
// Get the size of the name value.
//
status = ClusterRegQueryValue( networkKey,
CLUSREG_NAME_NET_NAME,
&type,
NULL,
&nameLength );
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
//
// Allocate memory for the network name.
//
networkName = LocalAlloc( LMEM_FIXED, nameLength );
if ( networkName == NULL ) {
status = GetLastError();
goto error_exit;
}
//
// Read the name value.
//
status = ClusterRegQueryValue( networkKey,
CLUSREG_NAME_NET_NAME,
&type,
(LPBYTE) networkName,
&nameLength );
if ( status != ERROR_SUCCESS ) {
LocalFree( networkName );
networkName = NULL;
goto error_exit;
}
break;
}
}
error_exit:
if ( networkKey != NULL ) {
ClusterRegCloseKey( networkKey );
}
if ( status != ERROR_SUCCESS ) {
SetLastError( status );
}
return(networkName);
} // IpaGetNameOfNetwork
DWORD
IpaGetRoleOfNetwork(
IN OUT PIPA_RESOURCE ResourceEntry,
IN LPCWSTR NetworkId,
OUT PDWORD NetworkRole
)
/*++
Routine Description:
Get the name of a network from its GUID.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
NetworkId - Supplies the ID of the network.
NetworkRole - Supplies network role to be filled in
Return Value:
ERROR_SUCCESS if function completes successfully
Win32 error code if function fails
--*/
{
DWORD status;
DWORD ival;
DWORD type;
DWORD nameLength;
WCHAR name[256];
DWORD roleSize;
HKEY networkKey = NULL;
FILETIME fileTime;
//
// Enumerate the networks, looking for the specified GUID.
//
for ( ival = 0 ; ; ival++ ) {
nameLength = sizeof(name);
status = ClusterRegEnumKey( ResourceEntry->NetworksKey,
ival,
name,
&nameLength,
&fileTime );
if ( status == ERROR_MORE_DATA ) {
continue;
}
if ( status != ERROR_SUCCESS ) {
break;
}
//
// If we found a match, open the key and read the name.
//
if ( lstrcmpiW( name, NetworkId ) == 0 ) {
status = ClusterRegOpenKey( ResourceEntry->NetworksKey,
name,
KEY_READ,
&networkKey );
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
//
// Read the role value.
//
roleSize = sizeof(*NetworkRole);
status = ClusterRegQueryValue( networkKey,
CLUSREG_NAME_NET_ROLE,
&type,
(LPBYTE) NetworkRole,
&roleSize);
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
break;
}
}
error_exit:
if ( networkKey != NULL ) {
ClusterRegCloseKey( networkKey );
}
if ( status != ERROR_SUCCESS ) {
SetLastError( status );
}
return(status);
} // IpaGetRoleOfNetwork
PWCHAR
WcsDup(
IN PWCHAR str
)
/*++
Routine Description:
Duplicates the string.
It does the same as _wcsdup, except that
it uses LocalAlloc for allocation
Arguments:
str - string to be copied
Return Value:
String allocated using LocalAlloc() containing the copy
of str.
NULL - not enough memory
--*/
{
UINT n = (wcslen(str) + 1) * sizeof(WCHAR);
PWCHAR result = LocalAlloc( LMEM_FIXED , n );
if (result) {
CopyMemory( result, str, n );
}
return result;
}
// The automatch mask determines whether the role/address match is
// higher or lower than the guid match.
#define IPADDR_MATCHNETGUID_NOTOVERRIDE 0x1
#define IPADDR_MATCHNETADDR 0x2
#define IPADDR_MATCHNETROLE 0x4
#define IPADDR_MATCHNETGUID_OVERRIDE 0x8
#define IPADDR_MATCHNETGUID ( IPADDR_MATCHNETGUID_NOTOVERRIDE | \
IPADDR_MATCHNETGUID_OVERRIDE )
#define IPADDR_ADDRMATCH_OVERRIDEMASK (~(IPADDR_MATCHNETGUID_NOTOVERRIDE))
#define IPADDR_ADDRMATCH_NOTOVERRIDEMASK (~(IPADDR_MATCHNETGUID_OVERRIDE))
DWORD
IpaPatchNetworkGuidIfNecessary(
IN OUT PIPA_RESOURCE ResourceEntry,
IN OUT PIPA_PRIVATE_PROPS props
)
/*++
Routine Description:
Find the best-matching network for this resource in the cluster
database. The match criteria depends on the OverrideAutomatch
private property.
If OverrideAutomatch is not set (default), the criteria is as
follows:
1. Resource address and mask match network mask. Network allows
client access.
2. Resource network guid matches cluster database network guid.
Network allows client access.
3. Resource address and mask match network mask. Network does
not allow client access.
4. Resource network guid matches cluster database network guid.
Network does not allow client access.
If OverrideAutomatch is set, the criteria is as follows:
1. Resource network guid matches cluster database network guid.
Network allows client access.
2. Resource network guid matches cluster database network guid.
Network does not allow client access.
3. Resource address and mask match network mask. Network allows
client access.
4. Resource address and mask match network mask. Network does
not allow client access.
If a network is chosen whose role does not allow client access,
the guid will be patched, but an online will be forbidden by
the caller of this routine.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
props - Supplies IP address properties.
Return Value:
String allocated using LocalAlloc() containing the name of the
network.
NULL - An error occurred getting the name of the network. Call
GetLastError() for more details.
--*/
{
DWORD status = ERROR_SUCCESS;
DWORD ival;
DWORD type;
DWORD bufLength;
WCHAR buf[256];
DWORD nameLength;
WCHAR name[256];
PWCHAR match = NULL;
ULONG networkAddr;
ULONG networkMask;
ULONG ipAddr;
ULONG ipAddrMask;
ULONG networkRole;
DWORD bestMatchFlags = 0;
DWORD overrideMask = 0;
DWORD bestPossibleMatch = 0;
HKEY networkKey = NULL;
FILETIME fileTime;
if (props == NULL) {
return ERROR_SUCCESS;
}
if ( props->NetworkString == NULL ) {
return ERROR_SUCCESS;
}
if ( props->AddressString == NULL
|| !UnicodeInetAddr(props->AddressString, &ipAddr) )
{
return ERROR_SUCCESS;
}
if ( props->SubnetMaskString == NULL
|| !UnicodeInetAddr(props->SubnetMaskString, &ipAddrMask) )
{
return ERROR_SUCCESS;
}
//
// Determine whether we are overriding the address automatch.
//
if ( props->OverrideAutomatch ) {
overrideMask = IPADDR_ADDRMATCH_OVERRIDEMASK;
bestPossibleMatch =
(IPADDR_MATCHNETGUID & overrideMask) | IPADDR_MATCHNETROLE;
} else {
overrideMask = IPADDR_ADDRMATCH_NOTOVERRIDEMASK;
bestPossibleMatch = IPADDR_MATCHNETADDR |
(IPADDR_MATCHNETGUID & overrideMask) |
IPADDR_MATCHNETROLE;
}
//
// Enumerate the networks, looking for the specified GUID.
//
for ( ival = 0 ; ; ival++ ) {
DWORD curMatchFlags = 0;
nameLength = sizeof(name);
status = ClusterRegEnumKey( ResourceEntry->NetworksKey,
ival,
name,
&nameLength,
&fileTime );
if ( status == ERROR_MORE_DATA ) {
continue;
}
if ( status != ERROR_SUCCESS ) {
break;
}
//
// If we found a guid match, we will remember it but still
// look for an address and role match.
//
if ( lstrcmpiW( name, props->NetworkString ) == 0 ) {
curMatchFlags |= IPADDR_MATCHNETGUID;
}
if ( networkKey != NULL ) {
ClusterRegCloseKey( networkKey );
networkKey = NULL;
}
//
// Open network key to get properties.
//
status = ClusterRegOpenKey( ResourceEntry->NetworksKey,
name,
KEY_READ,
&networkKey );
if ( status != ERROR_SUCCESS ) {
continue;
}
//
// Get the network role.
//
bufLength = sizeof(networkRole);
status = ClusterRegQueryValue( networkKey,
CLUSREG_NAME_NET_ROLE,
&type,
(LPBYTE)&networkRole,
&bufLength );
if ( status != ERROR_SUCCESS || type != REG_DWORD )
{
continue;
}
//
// Verify that the role of this network allows IP address
// resources.
//
if ( networkRole == ClusterNetworkRoleClientAccess ||
networkRole == ClusterNetworkRoleInternalAndClient ) {
curMatchFlags |= IPADDR_MATCHNETROLE;
}
//
// Check whether ip address fits this network.
// Get the network address
//
bufLength = sizeof(buf);
status = ClusterRegQueryValue( networkKey,
CLUSREG_NAME_NET_ADDRESS,
&type,
(LPBYTE)buf,
&bufLength );
if ( status != ERROR_SUCCESS
|| !UnicodeInetAddr(buf, &networkAddr) )
{
continue;
}
//
// Get subnet mask
//
bufLength = sizeof(buf);
status = ClusterRegQueryValue( networkKey,
CLUSREG_NAME_NET_ADDRESS_MASK,
&type,
(LPBYTE)buf,
&bufLength );
if ( status != ERROR_SUCCESS
|| !UnicodeInetAddr(buf, &networkMask) )
{
continue;
}
(IpaLogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Checking for network match: network masks %1!08X!=%2!08X! "
L"and addresses %3!08X!^%4!08X!, role %5!u!.\n",
ipAddrMask, networkMask,
ipAddr, networkAddr,
networkRole
);
if ( (networkMask == ipAddrMask) &&
((ipAddr ^ networkAddr) & networkMask) == 0 ) {
//
// The resource address matches the current network.
//
curMatchFlags |= IPADDR_MATCHNETADDR;
}
//
// Adjust the flags for whether we are overriding automatch.
//
curMatchFlags &= overrideMask;
//
// If only the role matched, we cannot use this network.
//
if ( curMatchFlags == IPADDR_MATCHNETROLE ) {
continue;
}
//
// If we have already seen a better match, keep searching.
//
if ( curMatchFlags < bestMatchFlags ) {
continue;
}
//
// This is the best match so far.
//
bestMatchFlags = curMatchFlags;
//
// Create a string with its name if it's
// not a guid match. (For a guid match, the name
// is already stored in the resource data structure).
//
if ( !(curMatchFlags & IPADDR_MATCHNETGUID) ) {
if ( match ) {
LocalFree( match );
}
match = WcsDup( name );
}
//
// If this is an unbeatable match, stop searching.
//
if ( (curMatchFlags & bestPossibleMatch) == bestPossibleMatch ) {
break;
}
}
ASSERT( bestMatchFlags != IPADDR_MATCHNETROLE );
if ( status != ERROR_SUCCESS && bestMatchFlags ) {
//
// We have at least one match. Update status.
//
status = ERROR_SUCCESS;
}
if ( !(bestMatchFlags & IPADDR_MATCHNETGUID) && bestMatchFlags ) {
LPWSTR networkName = NULL;
//
// We have a match, but it's not with the network GUID.
// We need to patch network information
//
LocalFree(props->NetworkString);
props->NetworkString = match;
status = ClusterRegSetValue(
ResourceEntry->ParametersKey,
CLUSREG_NAME_IPADDR_NETWORK,
REG_SZ,
(LPBYTE) match,
(wcslen(match) + 1) * sizeof(WCHAR)
);
(IpaLogEvent)(
ResourceEntry->ResourceHandle,
LOG_WARNING,
L"Patch with network GUID %2!ws!, status %1!u!.\n",
status,
match
);
match = NULL;
//
// Write an event log entry reporting the change.
//
networkName = IpaGetNameOfNetwork(
ResourceEntry,
props->NetworkString
);
if ( networkName != NULL ) {
ClusResLogSystemEventByKey1(
ResourceEntry->ResourceKey,
LOG_UNUSUAL,
RES_IPADDR_PATCHED_NETWORK,
networkName
);
LocalFree(networkName);
}
}
if ( networkKey != NULL ) {
ClusterRegCloseKey( networkKey );
}
if ( status != ERROR_SUCCESS ) {
SetLastError( status );
}
if (match != NULL) {
LocalFree(match);
}
return(status);
} // IpaPatchNetworkGuidIfNecessary
LPWSTR
IpaGetNameOfNetworkPatchGuidIfNecessary(
IN OUT PIPA_RESOURCE ResourceEntry,
IN OUT PIPA_PRIVATE_PROPS props
)
/*++
Routine Description:
Get the name of a network from its GUID.
If the guid cannot be found, it will try to find
appropriate network using IpaPatchNetworkGuidIfNecessary routine
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
props - Supplies IP address properties.
Return Value:
String allocated using LocalAlloc() containing the name of the
network.
NULL - An error occurred getting the name of the network. Call
GetLastError() for more details.
--*/
{
DWORD status;
LPWSTR result = IpaGetNameOfNetwork(ResourceEntry, props->NetworkString);
if (result) {
return result;
}
status = IpaPatchNetworkGuidIfNecessary(ResourceEntry, props);
if (status != ERROR_SUCCESS) {
SetLastError( status );
return 0;
}
return IpaGetNameOfNetwork(ResourceEntry, props->NetworkString);
} // IpaGetNameOfNetworkPatchGuidIfNecessary
LPWSTR
IpaGetIdOfNetwork(
IN OUT PIPA_RESOURCE ResourceEntry,
IN LPCWSTR NetworkName
)
/*++
Routine Description:
Get the ID of a network from its name.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
NetworkName - Supplies the name of the network.
Return Value:
String allocated using LocalAlloc() containing the name of the
network.
NULL - An error occurred getting the name of the network. Call
GetLastError() for more details.
--*/
{
DWORD status;
DWORD networkIdLength;
LPWSTR networkId = NULL;
HCLUSTER hcluster = NULL;
HNETWORK hnetwork = NULL;
//
// Open the cluster.
//
hcluster = OpenCluster( NULL );
if ( hcluster == NULL ) {
status = GetLastError();
goto error_exit;
}
//
// Open the network.
//
hnetwork = OpenClusterNetwork( hcluster, NetworkName );
if ( hnetwork == NULL ) {
status = GetLastError();
goto error_exit;
}
//
// Get the network ID length.
//
networkIdLength = 0;
status = GetClusterNetworkId( hnetwork,
NULL,
&networkIdLength );
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
//
// Allocate a string buffer.
//
networkId = LocalAlloc( LMEM_FIXED, (networkIdLength + 1) * sizeof(WCHAR) );
if ( networkId == NULL ) {
status = GetLastError();
goto error_exit;
}
networkIdLength++;
//
// Get the network ID.
//
status = GetClusterNetworkId( hnetwork,
networkId,
&networkIdLength );
if ( status != ERROR_SUCCESS ) {
LocalFree( networkId );
networkId = NULL;
}
error_exit:
if ( hnetwork != NULL ) {
CloseClusterNetwork( hnetwork );
}
if ( hcluster != NULL ) {
CloseCluster( hcluster );
}
return( networkId );
} // IpaGetIdOfNetwork
VOID
IpaDeleteNte(
IN OUT LPDWORD NteContext,
IN HKEY NodeParametersKey,
IN RESOURCE_HANDLE ResourceHandle
)
/*++
Routine Description:
Deletes a previously created NTE.
Arguments:
NteContext - A pointer to a variable containing the context value
identifying the NTE to delete.
NodeParametersKey - An open handle to the resource's node-specific
parameters key.
ResourceHandle - The Resource Monitor handle associated with this resource.
Return Value:
None.
--*/
{
DWORD status;
ASSERT(*NteContext != INVALID_NTE_CONTEXT);
ASSERT(ResourceHandle != NULL);
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Deleting IP interface %1!u!.\n",
*NteContext
);
status = TcpipDeleteNTE(*NteContext);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_WARNING,
L"Failed to delete IP interface %1!u!, status %2!u!.\n",
*NteContext,
status
);
}
*NteContext = INVALID_NTE_CONTEXT;
//
// Clear the NTE information from the registry
//
if (NodeParametersKey != NULL) {
status = ClusterRegDeleteValue(
NodeParametersKey,
L"InterfaceContext"
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_WARNING,
L"Failed to delete IP interface information from database, status %1!u!.\n",
status
);
}
}
return;
} // IpaDeleteNte
DWORD
IpaCreateNte(
IN LPWSTR AdapterId,
IN HKEY NodeParametersKey,
IN RESOURCE_HANDLE ResourceHandle,
OUT LPDWORD NteContext,
OUT LPDWORD NteInstance
)
/*++
Routine Description:
Creates a new NTE to hold an IP address.
Arguments:
AdapterId - A pointer to a buffer containing the unicode name
of the adapter on which the NTE is to be created.
NodeParametersKey - An open handle to the resource's node-specific
parameters key.
ResourceHandle - The Resource Monitor handle associated with this resource.
NteContext - A pointer to a variable into which to place the context value
which identifies the new NTE.
NteInstance - A pointer to a variable into which to place the instance value
which identifies the new NTE.
Return Value:
ERROR_SUCCESS if the routine is successful.
A Win32 error code otherwise.
--*/
{
DWORD status;
*NteContext = INVALID_NTE_CONTEXT;
status = TcpipAddNTE(
AdapterId,
0,
0,
NteContext,
NteInstance
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to create new IP interface, status %1!u!\n",
status);
return(status);
}
//
// Write the NTE information to the registry
//
status = ClusterRegSetValue(
NodeParametersKey,
L"InterfaceContext",
REG_DWORD,
(LPBYTE) NteContext,
sizeof(DWORD)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to write IP interface information to database, status %1!u!.\n",
status
);
goto error_exit;
}
status = ClusterRegSetValue(
NodeParametersKey,
L"InterfaceInstance",
REG_DWORD,
(LPBYTE) NteInstance,
sizeof(DWORD)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to write IP interface information to database, status %1!u!.\n",
status
);
goto error_exit;
}
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Created IP interface %1!u! (instance 0x%2!08X!).\n",
*NteContext,
*NteInstance
);
return(ERROR_SUCCESS);
error_exit:
if (*NteContext != INVALID_NTE_CONTEXT) {
IpaDeleteNte(
NteContext,
NodeParametersKey,
ResourceHandle
);
}
return(status);
}
VOID
IpaDeleteNbtInterface(
IN OUT LPWSTR * NbtDeviceName,
IN HKEY NodeParametersKey,
IN RESOURCE_HANDLE ResourceHandle
)
/*++
Routine Description:
Deletes an NBT device (interface).
Arguments:
NbtDeviceName - A pointer to a buffer containing the unicode name
of the NBT device to delete.
NodeParametersKey - An open handle to the resource's node-specific
parameters key.
ResourceHandle - The Resource Monitor handle associated with this resource.
Return Value:
None.
--*/
{
DWORD status;
ASSERT(*NbtDeviceName != NULL);
ASSERT(ResourceHandle != NULL);
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Deleting NBT interface %1!ws!.\n",
*NbtDeviceName
);
status = NbtDeleteInterface(*NbtDeviceName);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_WARNING,
L"Failed to delete NBT interface %1!ws!, status %2!u!.\n",
*NbtDeviceName,
status
);
}
LocalFree(*NbtDeviceName);
*NbtDeviceName = NULL;
//
// Clear the interface information from the registry
//
if (NodeParametersKey != NULL) {
status = ClusterRegDeleteValue(
NodeParametersKey,
L"NbtDeviceName"
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_WARNING,
L"Failed to delete NBT interface information from database, status %1!u!.\n",
status
);
}
}
return;
} // IpaDeleteNbtInterface
DWORD
IpaCreateNbtInterface(
IN HKEY NodeParametersKey,
IN RESOURCE_HANDLE ResourceHandle,
OUT LPWSTR * NbtDeviceName,
OUT LPDWORD NbtDeviceInstance
)
/*++
Routine Description:
Creates a new NBT device (interface) to be bound to an IP address.
Arguments:
NodeParametersKey - An open handle to the resource's node-specific
parameters key.
ResourceHandle - The Resource Monitor handle associated with this resource.
NbtDeviceName - A pointer to a buffer into which to place the unicode name
of the new NBT device.
NbtDeviceInstance - A pointer to a variable into which to place the instance
value which identifies the new NBT device.
Return Value:
ERROR_SUCCESS if the routine is successful.
A Win32 error code otherwise.
--*/
{
DWORD status;
DWORD deviceNameSize = 38; // size of L"\\Device\\NetBt_Ifxx\0"
*NbtDeviceName = NULL;
do {
if (*NbtDeviceName != NULL) {
LocalFree(*NbtDeviceName);
*NbtDeviceName = NULL;
}
*NbtDeviceName = LocalAlloc(LMEM_FIXED, deviceNameSize);
if (*NbtDeviceName == NULL) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to allocate memory.\n");
return(ERROR_NOT_ENOUGH_MEMORY);
}
status = NbtAddInterface(
*NbtDeviceName,
&deviceNameSize,
NbtDeviceInstance
);
} while (status == STATUS_BUFFER_TOO_SMALL);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to create new NBT interface, status %1!u!\n",
status
);
if (*NbtDeviceName != NULL) {
LocalFree(*NbtDeviceName);
*NbtDeviceName = NULL;
}
return(status);
}
status = ClusterRegSetValue(
NodeParametersKey,
L"NbtDeviceName",
REG_SZ,
(LPBYTE) *NbtDeviceName,
(lstrlenW(*NbtDeviceName) + 1) * sizeof(WCHAR)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to write NBT interface information to database, status %1!u!.\n",
status
);
goto error_exit;
}
status = ClusterRegSetValue(
NodeParametersKey,
L"NbtDeviceInstance",
REG_DWORD,
(LPBYTE) NbtDeviceInstance,
sizeof(DWORD)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to write NBT interface information to database, status %1!u!.\n",
status
);
goto error_exit;
}
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Created NBT interface %1!ws! (instance 0x%2!08X!).\n",
*NbtDeviceName,
*NbtDeviceInstance
);
return(ERROR_SUCCESS);
error_exit:
if (*NbtDeviceName != NULL) {
IpaDeleteNbtInterface(
NbtDeviceName,
NodeParametersKey,
ResourceHandle
);
}
return(status);
}
VOID
IpaLastOfflineCleanup(
VOID
)
/*++
Notes:
Called with IpaGlobalLock held.
Returns with IpaGlobalLock released.
--*/
{
HCHANGE notifyHandle = IpaClusterNotifyHandle;
HANDLE workerThreadHandle = IpaWorkerThreadHandle;
if (!IsListEmpty(&IpaResourceList)) {
PIPA_RESOURCE resource;
resource = CONTAINING_RECORD(
IpaResourceList.Flink,
IPA_RESOURCE,
Linkage
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"All resources offline - cleaning up\n"
);
}
IpaClusterNotifyHandle = NULL;
IpaWorkerThreadHandle = NULL;
IpaReleaseGlobalLock();
if (notifyHandle != NULL) {
CloseClusterNotifyPort(notifyHandle);
}
if (workerThreadHandle != NULL) {
WaitForSingleObject(workerThreadHandle, INFINITE);
CloseHandle(workerThreadHandle);
}
return;
} // IpaLastOfflineCleanup
DWORD
IpaFirstOnlineInit(
IN RESOURCE_HANDLE ResourceHandle
)
/*++
Notes:
Called with IpaGlobalLock held.
Returns with IpaGlobalLock released.
--*/
{
DWORD status = ERROR_SUCCESS;
DWORD threadId;
IpaClusterNotifyHandle = CreateClusterNotifyPort(
INVALID_HANDLE_VALUE,
IpaClusterHandle,
CLUSTER_CHANGE_HANDLE_CLOSE,
0
);
if (IpaClusterNotifyHandle == NULL) {
status = GetLastError();
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to create cluster notify port, status %1!u!.\n",
status
);
goto error_exit;
}
else {
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Created cluster notify port.\n"
);
}
IpaWorkerThreadHandle = CreateThread(
NULL,
0,
IpaWorkerThread,
NULL,
0,
&threadId
);
if (IpaWorkerThreadHandle == NULL) {
status = GetLastError();
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to create worker thread, status %1!u!.\n",
status
);
goto error_exit;
}
else {
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Created worker thread.\n"
);
}
IpaReleaseGlobalLock();
return(ERROR_SUCCESS);
error_exit:
IpaLastOfflineCleanup();
//
// The lock was released.
//
return(status);
} // IpaFirstOnlineInit
PIPA_RESOURCE
IpaFindResourceInList(
PVOID Key
)
{
PIPA_RESOURCE resource;
PLIST_ENTRY entry;
for ( entry = IpaResourceList.Flink;
entry != &IpaResourceList;
entry = entry->Flink
)
{
resource = CONTAINING_RECORD(
entry,
IPA_RESOURCE,
Linkage
);
if (resource == Key) {
return(resource);
}
}
return(NULL);
} // IpaFindResourceInList
VOID
IpaValidateAndOfflineInterfaces(
IN PIPA_RESOURCE Resource
)
{
DWORD status;
//
// Take care of NBT first.
//
if (Resource->NbtDeviceName != NULL) {
DWORD instance;
IPAddr boundAddress;
//
// Make sure that this is still our interface.
//
status = NbtGetInterfaceInfo(
Resource->NbtDeviceName,
&boundAddress,
&instance
);
if ( (status == ERROR_SUCCESS) &&
(Resource->NbtDeviceInstance == instance)
)
{
//
// Clear the WINS addresses
//
status = NbtSetWinsAddrInterface(Resource->NbtDeviceName, 0, 0);
if (status != NO_ERROR) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Failed to clear WINS addresses for NBT device %1!ws!, status %2!u!.\n",
Resource->NbtDeviceName,
status
);
}
//
// Unbind the interface from IP if necessary
//
if (boundAddress != 0) {
status = NbtBindInterface(Resource->NbtDeviceName, 0, 0);
if (status != ERROR_SUCCESS) {
//
// Delete the interface, since it is misbehaving.
//
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Failed to unbind NBT device %1!ws!, status %2!u!.\n",
Resource->NbtDeviceName,
status
);
IpaDeleteNbtInterface(
&(Resource->NbtDeviceName),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
}
}
}
else {
//
// Querying the NBT interface failed. See if we can determine
// why.
//
if (status == ERROR_WORKING_SET_QUOTA
|| status == ERROR_NO_SYSTEM_RESOURCES) {
//
// The NBT ioctl probably failed due to low resources.
// Leave record of the NBT interface in our database. We
// will clean it up next time we try to bring this resource
// on-line or (via clusnet) when the cluster service shuts
// down.
//
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"NBT interface %1!ws! (instance 0x%2!08X!) could not be queried, status %3!u!.\n",
Resource->NbtDeviceName,
Resource->NbtDeviceInstance,
status
);
}
else {
//
// The interface is no longer valid or it isn't ours.
// Forget about it.
//
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"NBT interface %1!ws! (instance 0x%2!08X!) is no longer valid, status %3!u!.\n",
Resource->NbtDeviceName,
Resource->NbtDeviceInstance,
status
);
LocalFree(Resource->NbtDeviceName);
Resource->NbtDeviceName = NULL;
if (Resource->NodeParametersKey != NULL) {
status = ClusterRegDeleteValue(
Resource->NodeParametersKey,
L"NbtDeviceName"
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Failed to delete NBT interface information from database, status %1!u!.\n",
status
);
}
}
}
}
}
//
// Now take care of IP
//
if (Resource->NteContext != INVALID_NTE_CONTEXT) {
TCPIP_NTE_INFO nteInfo;
//
// Make sure that this is still our interface.
//
status = TcpipGetNTEInfo(
Resource->NteContext,
&nteInfo
);
if ( (status == ERROR_SUCCESS) &&
(nteInfo.Instance == Resource->NteInstance)
)
{
//
// In Windows 2000, TCP/IP ignores requests to set the address
// of an NTE if the underlying interface is disconnected.
// This can result in the same IP address being brought online
// on two different nodes. In order to workaround this bug
// in TCP/IP, we now delete the NTE during offline processing
// instead of reusing it.
//
// Note that IpaDeleteNte() invalidates the value
// of Resource->NteContext.
//
IpaDeleteNte(
&(Resource->NteContext),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
#if 0
//
// If the NTE is still online, take care of that.
//
if (nteInfo.Address != 0) {
status = TcpipSetNTEAddress(Resource->NteContext, 0, 0);
if (status != ERROR_SUCCESS) {
//
// Delete the interface, since it is misbehaving.
//
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Failed to clear address for IP Interface %1!u!, status %2!u!.\n",
Resource->NteContext,
status
);
IpaDeleteNte(
&(Resource->NteContext),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
}
}
#endif
}
else {
//
// The NTE is no longer valid or isn't ours. Forget about it.
//
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"IP interface %1!u! (instance 0x%2!08X!) is no longer valid.\n",
Resource->NteContext,
Resource->NteInstance
);
Resource->NteContext = INVALID_NTE_CONTEXT;
if (Resource->NodeParametersKey != NULL) {
status = ClusterRegDeleteValue(
Resource->NodeParametersKey,
L"InterfaceContext"
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Failed to delete IP interface information from database, status %1!u!.\n",
status
);
}
}
}
//
// Tell the DNS resolver to update its list of local ip addresses.
//
// BUGBUG - The DNS resolver should do this automatically based
// on PnP events in the Whistler release. Remove this code
// after verifiying that functionality.
//
// This issue is tracked with bug 97134.
// DnsNotifyResolver(0, 0);
DnsNotifyResolverClusterIp((IP_ADDRESS)Resource->Address, FALSE);
}
return;
} // IpaValidateAndOfflineInterfaces
DWORD
IpaGetNodeParameters(
PIPA_RESOURCE Resource,
BOOL OkToCreate
)
/*++
Routine Description:
get any node based parameters from the registry. We can't call create
during IpaOpen so this won't do much for the first open of a new resource.
Arguments:
Resource - pointer to IP internal resource data block
OkToCreate - true if we can use ClusterRegCreateKey instead of
ClusterRegOpenKey
Return Value:
success if everything worked ok
--*/
{
DWORD status;
if (Resource->NodeParametersKey == NULL) {
//
// create or open the resource's node-specific parameters key.
//
if ( OkToCreate ) {
status = ClusterRegCreateKey(Resource->ParametersKey,
Resource->NodeId,
0,
KEY_READ,
NULL,
&(Resource->NodeParametersKey),
NULL);
}
else {
status = ClusterRegOpenKey(Resource->ParametersKey,
Resource->NodeId,
KEY_READ,
&(Resource->NodeParametersKey));
}
if (status != NO_ERROR) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unable to %1!ws! node parameters key, status %2!u!.\n",
OkToCreate ? L"create" : L"open",
status
);
if ( !OkToCreate ) {
//
// we still need to init some values in the resource data
// block if open fails
//
Resource->NteContext = INVALID_NTE_CONTEXT;
Resource->NteInstance = 0;
Resource->NbtDeviceName = NULL;
Resource->NbtDeviceInstance = 0;
}
return(status);
}
}
//
// Read the old TCP/IP and NBT parameters.
//
status = ResUtilGetDwordValue(
Resource->NodeParametersKey,
L"InterfaceContext",
&(Resource->NteContext),
INVALID_NTE_CONTEXT
);
if (status == ERROR_SUCCESS) {
status = ResUtilGetDwordValue(
Resource->NodeParametersKey,
L"InterfaceInstance",
&(Resource->NteInstance),
0
);
if (status != ERROR_SUCCESS) {
Resource->NteContext = INVALID_NTE_CONTEXT;
}
}
// [RajDas] 493527 --> Free the NbtDeviceName string before it's reallocated.
if (Resource->NbtDeviceName != NULL) {
LocalFree(Resource->NbtDeviceName);
Resource->NbtDeviceName = NULL;
}
Resource->NbtDeviceName = ResUtilGetSzValue(
Resource->NodeParametersKey,
L"NbtDeviceName"
);
if (Resource->NbtDeviceName != NULL) {
status = ResUtilGetDwordValue(
Resource->NodeParametersKey,
L"NbtDeviceInstance",
&(Resource->NbtDeviceInstance),
0
);
if (status != ERROR_SUCCESS) {
LocalFree(Resource->NbtDeviceName);
Resource->NbtDeviceName = NULL;
}
}
return status;
}
DWORD
IpaInitializeInternalParameters(
PIPA_RESOURCE Resource
)
{
DWORD status;
ASSERT(Resource->ResourceKey != NULL);
ASSERT(Resource->ResourceHandle != NULL);
if (Resource->ParametersKey == NULL) {
//
// Open the resource's parameters key.
//
status = ClusterRegOpenKey(
Resource->ResourceKey,
CLUSREG_KEYNAME_PARAMETERS,
KEY_READ,
&(Resource->ParametersKey)
);
if (status != NO_ERROR) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unable to open parameters key, status %1!u!.\n",
status
);
return(status);
}
}
if (Resource->NodeParametersKey == NULL) {
status = IpaGetNodeParameters( Resource, FALSE );
}
Resource->InternalParametersInitialized = TRUE;
return(ERROR_SUCCESS);
} // IpaInitializeInternalParameters
VOID
IpaFreePrivateProperties(
IN PIPA_PRIVATE_PROPS PrivateProps
)
{
if (PrivateProps->NetworkString != NULL) {
LocalFree(PrivateProps->NetworkString);
PrivateProps->NetworkString = NULL;
}
if (PrivateProps->AddressString != NULL) {
LocalFree(PrivateProps->AddressString);
PrivateProps->AddressString = NULL;
}
if (PrivateProps->SubnetMaskString != NULL) {
LocalFree(PrivateProps->SubnetMaskString);
PrivateProps->SubnetMaskString = NULL;
}
return;
} // IpaFreePrivateProperties
VOID
IpaFreeLocalParameters(
IN PIPA_LOCAL_PARAMS LocalParams
)
{
if (LocalParams->InterfaceId != NULL) {
LocalFree(LocalParams->InterfaceId);
LocalParams->InterfaceId = NULL;
}
if (LocalParams->InterfaceName != NULL) {
LocalFree(LocalParams->InterfaceName);
LocalParams->InterfaceName = NULL;
}
if (LocalParams->AdapterName != NULL) {
LocalFree(LocalParams->AdapterName);
LocalParams->AdapterName = NULL;
}
if (LocalParams->AdapterId != NULL) {
LocalFree(LocalParams->AdapterId);
LocalParams->AdapterId = NULL;
}
return;
} // IpaFreeLocalParameters
DWORD
IpaGetLocalParameters(
IN PIPA_RESOURCE Resource,
IN OUT PIPA_LOCAL_PARAMS LocalParams
)
/*++
Routine Description:
Reads the local parameters needed to bring an IP address resource online.
Arguments:
Resource - Resource structure for the resource.
LocalParams - A pointer to a structure to fill in with the new
local parameters.
Return Value:
ERROR_SUCCESS if the routine is successful.
A Win32 error code otherwise.
--*/
{
DWORD status;
DWORD valueType;
LPWSTR deviceName;
DWORD deviceNameLength;
HKEY interfaceKey = NULL;
WCHAR networkId[NETWORK_ID_LENGTH + 1];
WCHAR nodeId[MAX_NODE_ID_LENGTH];
DWORD i;
DWORD valueLength;
DWORD type;
DWORD interfaceIdSize = (NETINTERFACE_ID_LENGTH + 1 ) * sizeof(WCHAR);
ZeroMemory(LocalParams, sizeof(IPA_LOCAL_PARAMS));
LocalParams->InterfaceId = LocalAlloc(LMEM_FIXED, interfaceIdSize);
if (LocalParams->InterfaceId == NULL) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Open: Unable to allocate memory for netinterface ID.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
//
// Enumerate the interface keys looking for the right one for this
// node/network.
//
for (i=0; ;i++) {
if (interfaceKey != NULL) {
ClusterRegCloseKey(interfaceKey); interfaceKey = NULL;
}
valueLength = interfaceIdSize;
status = ClusterRegEnumKey(
Resource->InterfacesKey,
i,
LocalParams->InterfaceId,
&valueLength,
NULL
);
if (status != ERROR_SUCCESS) {
if ( status == ERROR_NO_MORE_ITEMS ) {
status = ERROR_NETWORK_NOT_AVAILABLE;
}
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Open: Unable to find netinterface for node %1!ws! on network %2!ws!, status %3!u!.\n",
Resource->NodeId,
Resource->InternalPrivateProps.NetworkString,
status
);
goto error_exit;
}
//
// Open the enumerated interface key
//
status = ClusterRegOpenKey(
Resource->InterfacesKey,
LocalParams->InterfaceId,
KEY_READ,
&interfaceKey
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Open: Unable to open key for network interface %1!ws!, status %2!u!.\n",
LocalParams->InterfaceId,
status
);
continue;
}
//
// Read the node value.
//
valueLength = sizeof(nodeId);
status = ClusterRegQueryValue(
interfaceKey,
CLUSREG_NAME_NETIFACE_NODE,
&type,
(LPBYTE) &(nodeId[0]),
&valueLength
);
if ( status != ERROR_SUCCESS ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Open: Unable to read node value for netinterface %1!ws!, status %2!u!.\n",
LocalParams->InterfaceId,
status
);
continue;
}
if (wcscmp(Resource->NodeId, nodeId) != 0) {
continue;
}
//
// Read the network value.
//
valueLength = sizeof(networkId);
status = ClusterRegQueryValue(
interfaceKey,
CLUSREG_NAME_NETIFACE_NETWORK,
&type,
(LPBYTE) &(networkId[0]),
&valueLength
);
if ( status != ERROR_SUCCESS ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Open: Unable to read network value for netinterface %1!ws!, status %2!u!.\n",
LocalParams->InterfaceId,
status
);
continue;
}
if (wcscmp(
Resource->InternalPrivateProps.NetworkString,
networkId
) == 0
)
{
//
// Found the right interface key.
//
break;
}
}
//
// Read the adapter name for the interface.
//
LocalParams->AdapterName = ResUtilGetSzValue(
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_NAME
);
if (LocalParams->AdapterName == NULL) {
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Open: Unable to read adapter name parameter for interface %1!ws!, status %2!u!.\n",
LocalParams->InterfaceId,
status
);
goto error_exit;
}
//
// Read the adapter Id for the interface.
//
LocalParams->AdapterId = ResUtilGetSzValue(
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_ID
);
if (LocalParams->AdapterId == NULL) {
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Open: Unable to read adapter Id parameter for interface %1!ws!, status %2!u!.\n",
LocalParams->InterfaceId,
status
);
goto error_exit;
}
LocalParams->InterfaceName = ResUtilGetSzValue(
interfaceKey,
CLUSREG_NAME_NETIFACE_NAME
);
if (LocalParams->InterfaceName == NULL) {
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Open: Unable to read name for netinterface %1!ws!, status %2!u!.\n",
LocalParams->InterfaceId,
status
);
goto error_exit;
}
ClusterRegCloseKey(interfaceKey); interfaceKey = NULL;
//
// Get the WINS addresses for this interface.
//
deviceNameLength = sizeof(WCHAR) * ( lstrlenW(NbtDevicePrefix) +
lstrlenW(LocalParams->AdapterId) +
lstrlenW(NbtDeviceSuffix) + 1
);
deviceName = LocalAlloc(LMEM_FIXED, deviceNameLength);
if (deviceName == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unable to allocate memory for NBT device name.\n"
);
goto error_exit;
}
lstrcpyW(deviceName, NbtDevicePrefix);
lstrcatW(deviceName, LocalParams->AdapterId);
lstrcatW(deviceName, NbtDeviceSuffix);
status = NbtGetWinsAddresses(
deviceName,
&(LocalParams->NbtPrimaryWinsAddress),
&(LocalParams->NbtSecondaryWinsAddress)
);
LocalFree(deviceName);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Unable to determine WINS server addresses for adapter %1!ws!, status %2!u!\n",
LocalParams->AdapterName,
status
);
//
// NBT sets the WINS server addresses to loopback by default.
//
LocalParams->NbtPrimaryWinsAddress = inet_addr("127.0.0.1");
LocalParams->NbtSecondaryWinsAddress =
LocalParams->NbtPrimaryWinsAddress;
}
status = ERROR_SUCCESS;
error_exit:
if (interfaceKey != NULL) {
ClusterRegCloseKey(interfaceKey);
}
if (status != ERROR_SUCCESS) {
IpaFreeLocalParameters(LocalParams);
}
return(status);
} // IpaGetLocalParameters
//
// Primary Resource Functions
//
BOOLEAN
WINAPI
IpAddrDllEntryPoint(
IN HINSTANCE DllHandle,
IN DWORD Reason,
IN LPVOID Reserved
)
{
switch(Reason) {
case DLL_PROCESS_ATTACH:
return(IpaInit());
break;
case DLL_PROCESS_DETACH:
IpaCleanup();
break;
default:
break;
}
return(TRUE);
}
RESID
WINAPI
IpaOpen(
IN LPCWSTR ResourceName,
IN HKEY ResourceKey,
IN RESOURCE_HANDLE ResourceHandle
)
/*++
Routine Description:
Open routine for IP Address resource
Arguments:
ResourceName - supplies the resource name
ResourceKey - a registry key for access registry information for this
resource.
ResourceHandle - the resource handle to be supplied with SetResourceStatus
is called.
Return Value:
RESID of created resource
NULL on failure
--*/
{
DWORD status;
PIPA_RESOURCE resource = NULL;
DWORD nodeIdSize = MAX_NODE_ID_LENGTH + 1;
HKEY clusterKey = NULL;
IpaAcquireGlobalLock();
if (IpaOpenResourceCount == 0) {
ASSERT(IpaClusterHandle == NULL);
IpaClusterHandle = OpenCluster(NULL);
if (IpaClusterHandle == NULL) {
status = GetLastError();
IpaReleaseGlobalLock();
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open cluster handle, status %1!u!.\n",
status
);
return(0);
}
}
IpaOpenResourceCount++;
IpaReleaseGlobalLock();
resource = LocalAlloc(
(LMEM_FIXED | LMEM_ZEROINIT),
sizeof(IPA_RESOURCE)
);
if (resource == NULL) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Resource allocation failed.\n"
);
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return(0);
}
//
// Initialize known fields.
//
InitializeCriticalSection(&(resource->Lock));
resource->ResourceHandle = ResourceHandle;
resource->State = ClusterResourceOffline;
resource->NteContext = INVALID_NTE_CONTEXT;
//
// Initialize the Linkage field as a list head. This
// prevents an AV in IpaClose if IpaOpen fails before
// the resource is added to IpaResourceList.
//
InitializeListHead(&(resource->Linkage));
//
// Allocate an address string buffer.
//
resource->InternalPrivateProps.AddressString =
LocalAlloc(
LMEM_FIXED,
( (IpaMaxIpAddressStringLength + 1) *
sizeof(WCHAR)
));
if (resource->InternalPrivateProps.AddressString == NULL) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Resource allocation failed.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
lstrcpyW(resource->InternalPrivateProps.AddressString, L"[Unknown]");
//
// Figure out what node we're running on.
//
status = GetCurrentClusterNodeId(
&(resource->NodeId[0]),
&nodeIdSize
);
if ( status != ERROR_SUCCESS ) {
status = GetLastError();
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to get local node ID, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Open a private handle to our resource key so that we can get our
// name later if we need to log an event.
//
status = ClusterRegOpenKey(
ResourceKey,
L"",
KEY_READ,
&(resource->ResourceKey)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open resource key. Error: %1!u!.\n",
status
);
goto error_exit;
}
//
// Open a key to the networks portion of the cluster registry.
//
clusterKey = GetClusterKey(IpaClusterHandle, KEY_READ);
if (clusterKey == NULL) {
status = GetLastError();
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open cluster registry key, status %1!u!.\n",
status
);
goto error_exit;
}
status = ClusterRegOpenKey(
clusterKey,
L"Networks",
KEY_READ,
&(resource->NetworksKey)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open networks registry key, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Open a key to the interfaces portion of the cluster registry.
//
status = ClusterRegOpenKey(
clusterKey,
L"NetworkInterfaces",
KEY_READ,
&(resource->InterfacesKey)
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open network interfaces registry key, status %1!u!.\n",
status
);
goto error_exit;
}
ClusterRegCloseKey(clusterKey); clusterKey = NULL;
status = IpaInitializeInternalParameters(resource);
if (status == ERROR_SUCCESS) {
//
// Validate our TCP/IP and NBT parameters and clean up any old
// interfaces we left hanging around from the last run.
//
IpaValidateAndOfflineInterfaces(resource);
}
//
// Link the resource onto the global list.
//
IpaAcquireGlobalLock();
InsertTailList(&IpaResourceList, &(resource->Linkage));
IpaReleaseGlobalLock();
(IpaLogEvent)(
ResourceHandle,
LOG_INFORMATION,
L"Resource open, resource ID = %1!u!.\n",
resource
);
return(resource);
error_exit:
IpaClose((RESID) resource);
if (clusterKey != NULL) {
ClusterRegCloseKey(clusterKey);
}
SetLastError( status );
return(0);
} // IpaOpen
VOID
WINAPI
IpaDoOfflineProcessing(
IN PIPA_RESOURCE Resource,
IN RESOURCE_STATUS * ResourceStatus
)
/*++
Routine Description:
Final offline processing for IP Address resource.
Arguments:
Resource - supplies the resource it to be taken offline
Return Value:
None.
Notes:
Called with the resource lock held.
Returns with the resource lock released.
--*/
{
DWORD status = ERROR_SUCCESS;
ULONG address = 0, mask = 0;
HNETINTERFACE ifHandle;
ASSERT(Resource->State == ClusterResourceOfflinePending);
IpaValidateAndOfflineInterfaces(Resource);
//
// Make local copies of external resource handles
//
ifHandle = Resource->InterfaceHandle;
Resource->InterfaceHandle = NULL;
Resource->State = ClusterResourceOffline;
if (ResourceStatus != NULL) {
ResourceStatus->CheckPoint++;
ResourceStatus->ResourceState = ClusterResourceOffline;
(IpaSetResourceStatus)(Resource->ResourceHandle, ResourceStatus);
}
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"Address %1!ws! on adapter %2!ws! offline.\n",
Resource->InternalPrivateProps.AddressString,
( (Resource->LocalParams.AdapterName != NULL) ?
Resource->LocalParams.AdapterName : L"[Unknown]"
));
IpaReleaseResourceLock(Resource);
//
// Free external resources.
//
if (ifHandle != NULL) {
CloseClusterNetInterface(ifHandle);
}
IpaAcquireGlobalLock();
//
// If this is the last resource, cleanup the global state.
//
ASSERT(IpaOnlineResourceCount > 0);
if (--IpaOnlineResourceCount == 0) {
IpaLastOfflineCleanup();
//
// The lock was released.
//
}
else {
IpaReleaseGlobalLock();
}
return;
} // IpaDoOfflineProcessing
VOID
WINAPI
IpaInternalOffline(
IN PIPA_RESOURCE Resource
)
/*++
Routine Description:
Internal offline routine for IP Address resource.
Arguments:
Resource - supplies the resource it to be taken offline
Return Value:
None.
--*/
{
//
// Terminate the online thread, if it is running.
//
ClusWorkerTerminate(&(Resource->OnlineThread));
//
// Synchronize IpaOffline, IpaTerminate, and IpaWorkerThread.
//
IpaAcquireResourceLock(Resource);
if (Resource->State == ClusterResourceOffline) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"Resource is already offline.\n"
);
IpaReleaseResourceLock(Resource);
return;
}
Resource->State = ClusterResourceOfflinePending;
IpaDoOfflineProcessing(Resource, NULL);
//
// The lock was released.
//
return;
} // IpaInternalOffline
DWORD
WINAPI
IpaOffline(
IN RESID Resource
)
/*++
Routine Description:
Offline routine for IP Address resource.
Arguments:
Resource - supplies resource id to be taken offline.
Return Value:
ERROR_SUCCESS if successful.
A Win32 error code otherwise.
--*/
{
DWORD status;
PIPA_RESOURCE resource = (PIPA_RESOURCE) Resource;
if (resource != NULL) {
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"Taking resource offline...\n"
);
IpaInternalOffline(resource);
status = ERROR_SUCCESS;
}
else {
status = ERROR_RESOURCE_NOT_FOUND;
}
return(status);
} // IpaOffline
VOID
WINAPI
IpaTerminate(
IN RESID Resource
)
/*++
Routine Description:
Terminate routine for IP Address resource.
Arguments:
Resource - supplies resource id to be terminated
Return Value:
None.
--*/
{
PIPA_RESOURCE resource = (PIPA_RESOURCE) Resource;
if (resource != NULL) {
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"Terminating resource...\n"
);
IpaInternalOffline(resource);
}
return;
} // IpaTerminate
DWORD
IpaOnlineThread(
IN PCLUS_WORKER pWorker,
IN PIPA_RESOURCE Resource
)
/*++
Routine Description:
Brings an IP address resource online.
Arguments:
pWorker - Supplies the worker structure
Resource - A pointer to the IPA_RESOURCE block for this resource.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
DWORD status = ERROR_SUCCESS;
DWORD i;
RESOURCE_EXIT_STATE exit;
RESOURCE_STATUS resourceStatus;
BOOL retried;
IPA_LOCAL_PARAMS newParams;
PIPA_LOCAL_PARAMS localParams = NULL;
PIPA_PRIVATE_PROPS privateProps = NULL;
LPWSTR nameOfPropInError = NULL;
DWORD networkRole;
CLUSTER_NETINTERFACE_STATE state;
BOOL firstOnline = FALSE;
DWORD numTries;
ZeroMemory(&newParams, sizeof(newParams));
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"Online thread running.\n",
Resource
);
IpaAcquireGlobalLock();
IpaAcquireResourceLock(Resource);
if (IpaOnlineResourceCount++ == 0) {
firstOnline = TRUE;
}
ResUtilInitializeResourceStatus(&resourceStatus);
resourceStatus.CheckPoint = 1;
resourceStatus.ResourceState = ClusterResourceOnlinePending;
exit = (IpaSetResourceStatus)(Resource->ResourceHandle, &resourceStatus);
if ( exit == ResourceExitStateTerminate ) {
IpaReleaseGlobalLock();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online thread aborted.\n"
);
status = ERROR_OPERATION_ABORTED;
goto error_exit;
}
//
// If this is the first resource to go online in this process,
// initialize the global state.
//
if (firstOnline) {
status = IpaFirstOnlineInit(Resource->ResourceHandle);
//
// The global lock was released.
//
if (status != ERROR_SUCCESS) {
goto error_exit;
}
}
else {
IpaReleaseGlobalLock();
}
resourceStatus.CheckPoint++;
exit = (IpaSetResourceStatus)(Resource->ResourceHandle, &resourceStatus);
if ( exit == ResourceExitStateTerminate ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online thread aborted.\n"
);
status = ERROR_OPERATION_ABORTED;
goto error_exit;
}
//
// Check to see if the online operation was aborted while this thread
// was starting up.
//
if (ClusWorkerCheckTerminate(pWorker)) {
status = ERROR_OPERATION_ABORTED;
Resource->State = ClusterResourceOfflinePending;
goto error_exit;
}
if (!Resource->InternalParametersInitialized) {
status = IpaInitializeInternalParameters(Resource);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
}
else {
status = IpaGetNodeParameters( Resource, TRUE );
}
//
// Make sure the old interfaces are valid and offline.
//
IpaValidateAndOfflineInterfaces(Resource);
//
// Read and verify the resource's private properties.
//
privateProps = &(Resource->InternalPrivateProps);
status = ResUtilGetPropertiesToParameterBlock(
Resource->ParametersKey,
IpaResourcePrivateProperties,
(LPBYTE) privateProps,
TRUE, // CheckForRequiredProperties
&nameOfPropInError
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unable to read the '%1' property. Error: %2!u!.\n",
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
status
);
goto error_exit;
}
Resource->EnableNetbios = privateProps->EnableNetbios;
//
// Convert the address and subnet mask strings to binary.
//
status = ClRtlTcpipStringToAddress(
privateProps->AddressString,
&(Resource->Address)
);
if (status != ERROR_SUCCESS) {
status = ERROR_INVALID_PARAMETER;
ClusResLogSystemEventByKeyData(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_INVALID_ADDRESS,
sizeof(Resource->Address),
&(Resource->Address)
);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Invalid address %1!ws!.\n",
privateProps->AddressString
);
goto error_exit;
}
status = ClRtlTcpipStringToAddress(
privateProps->SubnetMaskString,
&(Resource->SubnetMask)
);
if (status != ERROR_SUCCESS) {
status = ERROR_INVALID_PARAMETER;
ClusResLogSystemEventByKeyData(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_INVALID_SUBNET,
sizeof(Resource->SubnetMask),
&(Resource->SubnetMask)
);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Invalid subnet mask %1!ws!.\n",
privateProps->SubnetMaskString
);
goto error_exit;
}
status = IpaPatchNetworkGuidIfNecessary(Resource, privateProps);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"IpaPatchNetworkGuidIfNecessary failed, status %1!d!.\n",
status
);
}
//
// The network has been chosen. Verify that its role allows
// IP address resources.
//
status = IpaGetRoleOfNetwork(
Resource,
privateProps->NetworkString,
&networkRole
);
if ( status != ERROR_SUCCESS ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"IpaGetRoleOfNetwork failed for network %1!ws!, "
L"status %2!d!.\n",
privateProps->NetworkString,
status
);
goto error_exit;
} else if ( networkRole != ClusterNetworkRoleClientAccess &&
networkRole != ClusterNetworkRoleInternalAndClient ) {
LPWSTR networkName = NULL;
status = ERROR_CLUSTER_INVALID_NETWORK;
networkName = IpaGetNameOfNetwork(
Resource,
privateProps->NetworkString
);
if ( networkName != NULL ) {
ClusResLogSystemEventByKeyData1(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_INVALID_NETWORK_ROLE,
sizeof(networkRole),
(LPBYTE) &networkRole,
networkName
);
}
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Cannot bring resource online because network %1!ws! "
L"(%2!ws!) has role %3!u!.\n",
privateProps->NetworkString,
(networkName != NULL) ? networkName : L"<Unknown>",
networkRole
);
if ( networkName != NULL ) {
LocalFree(networkName);
}
goto error_exit;
}
//
// Fetch the resource's parameters for the local node.
//
status = IpaGetLocalParameters(Resource, &newParams);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
localParams = &(Resource->LocalParams);
//
// Update the interface name.
//
if (localParams->InterfaceName != NULL) {
LocalFree(localParams->InterfaceName);
}
localParams->InterfaceName = newParams.InterfaceName;
newParams.InterfaceName = NULL;
//
// Update the interface ID.
//
if ( (localParams->InterfaceId != NULL) &&
(lstrcmp(localParams->InterfaceId, newParams.InterfaceId) != 0)
)
{
LocalFree(localParams->InterfaceId);
localParams->InterfaceId = NULL;
if (Resource->InterfaceHandle != NULL) {
CloseClusterNetInterface(Resource->InterfaceHandle);
Resource->InterfaceHandle = NULL;
}
}
if (localParams->InterfaceId == NULL) {
localParams->InterfaceId = newParams.InterfaceId;
newParams.InterfaceId = NULL;
}
//
// Update the interface handle.
//
if (Resource->InterfaceHandle == NULL) {
Resource->InterfaceHandle = OpenClusterNetInterface(
IpaClusterHandle,
localParams->InterfaceName
);
if (Resource->InterfaceHandle == NULL) {
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online: Unable to open object for netinterface %1!ws!, status %2!u!.\n",
localParams->InterfaceId,
status
);
goto error_exit;
}
else {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"Online: Opened object handle for netinterface %1!ws!.\n",
localParams->InterfaceId
);
}
}
//
// Register for state change notifications for the interface.
//
status = RegisterClusterNotify(
IpaClusterNotifyHandle,
( CLUSTER_CHANGE_NETINTERFACE_STATE |
CLUSTER_CHANGE_NETINTERFACE_DELETED
),
Resource->InterfaceHandle,
(DWORD_PTR) Resource
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online: Unable to register notification for netinterface %1!ws!, status %2!u!.\n",
localParams->InterfaceId,
status
);
goto error_exit;
}
else {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"Online: Registered notification for netinterface %1!ws!.\n",
localParams->InterfaceId
);
}
//
// Check if the interface has failed already. We will sleep for a while
// and retry under certain conditions. The network state can take a few
// seconds to settle.
//
numTries = 0;
for (;;) {
resourceStatus.CheckPoint++;
exit = (IpaSetResourceStatus)(
Resource->ResourceHandle,
&resourceStatus
);
if ( exit == ResourceExitStateTerminate ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online thread aborted.\n"
);
status = ERROR_OPERATION_ABORTED;
goto error_exit;
}
state = GetClusterNetInterfaceState(
Resource->InterfaceHandle
);
if (state == ClusterNetInterfaceUp) {
break;
}
else if (state == ClusterNetInterfaceUnavailable ||
state == ClusterNetInterfaceUnreachable )
{
PWCHAR stateName = ( state == ClusterNetInterfaceUnavailable ?
L"available" : L"reachable" );
if (++numTries <= 5) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"NetInterface %1!ws! is not %2!ws!. Wait & retry.\n",
Resource->LocalParams.InterfaceId,
stateName
);
Sleep(1000);
continue;
}
else {
status = ERROR_IO_DEVICE;
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Timed out waiting for NetInterface %1!ws! to be available. Failing resource.\n",
Resource->LocalParams.InterfaceId
);
goto error_exit;
}
}
else if (state == ClusterNetInterfaceFailed) {
status = ERROR_IO_DEVICE;
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"NetInterface %1!ws! has failed.\n",
Resource->LocalParams.InterfaceId
);
goto error_exit;
}
else if (state == ClusterNetInterfaceStateUnknown) {
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Failed to get state for netinterface %1!ws!, status %2!u!.\n",
Resource->LocalParams.InterfaceId,
status
);
goto error_exit;
}
else {
ASSERT(FALSE);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unrecognized state for netinterface %1!ws!, state %2!u!.\n",
Resource->LocalParams.InterfaceId,
state
);
status = ERROR_INVALID_PARAMETER;
goto error_exit;
}
}
Resource->FailureStatus = ERROR_SUCCESS;
//
// Update the adapter name parameter.
//
if (localParams->AdapterName != NULL) {
LocalFree(localParams->AdapterName);
}
localParams->AdapterName = newParams.AdapterName;
newParams.AdapterName = NULL;
//
// Update the adapter Id parameter.
//
if ((localParams->AdapterId == NULL) ||
(lstrcmpiW(localParams->AdapterId, newParams.AdapterId) != 0)) {
if (localParams->AdapterId != NULL) {
LocalFree(localParams->AdapterId);
}
localParams->AdapterId = newParams.AdapterId;
newParams.AdapterId = NULL;
if (Resource->NteContext != INVALID_NTE_CONTEXT) {
//
// Delete the old NTE.
//
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"Adapter Id has changed to %1!ws!.\n",
localParams->AdapterId
);
IpaDeleteNte(
&(Resource->NteContext),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
}
}
//
// Create a new NTE if we need one.
//
if (Resource->NteContext == INVALID_NTE_CONTEXT) {
status = IpaCreateNte(
localParams->AdapterId,
Resource->NodeParametersKey,
Resource->ResourceHandle,
&(Resource->NteContext),
&(Resource->NteInstance)
);
if (status != ERROR_SUCCESS) {
ClusResLogSystemEventByKeyData(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_NTE_CREATE_FAILED,
sizeof(status),
&status
);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Failed to created new IP interface, status %1!u!.\n",
status
);
goto error_exit;
}
}
//
// Create a new NBT interface if we need one.
//
if (privateProps->EnableNetbios) {
if (Resource->NbtDeviceName == NULL) {
status = IpaCreateNbtInterface(
Resource->NodeParametersKey,
Resource->ResourceHandle,
&(Resource->NbtDeviceName),
&(Resource->NbtDeviceInstance)
);
if (status != ERROR_SUCCESS) {
ClusResLogSystemEventByKeyData(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_NBT_INTERFACE_CREATE_FAILED,
sizeof(status),
&status
);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Failed to created new NBT interface, status %1!u!.\n",
status
);
goto error_exit;
}
}
}
else {
if (Resource->NbtDeviceName != NULL) {
IpaDeleteNbtInterface(
&(Resource->NbtDeviceName),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
}
}
//
// Update the resource's WINS parameters
//
localParams->NbtPrimaryWinsAddress = newParams.NbtPrimaryWinsAddress;
localParams->NbtSecondaryWinsAddress = newParams.NbtSecondaryWinsAddress;
//
// We have valid, offline interfaces to work with. Send out a few ICMP
// Echo requests to see if any other machine has this address online.
// If one does, we'll abort this online operation.
//
resourceStatus.CheckPoint++;
exit = (IpaSetResourceStatus)(Resource->ResourceHandle, &resourceStatus);
if ( exit == ResourceExitStateTerminate ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online thread aborted.\n"
);
status = ERROR_OPERATION_ABORTED;
goto error_exit;
}
retried = FALSE;
while (TRUE) {
status = TcpipSetNTEAddress(
Resource->NteContext,
Resource->Address,
Resource->SubnetMask
);
if(status == ERROR_SUCCESS)
break;
if (!retried ) {
//
// Check to see if the online operation was aborted while
// this thread was blocked.
//
if (ClusWorkerCheckTerminate(pWorker)) {
status = ERROR_OPERATION_ABORTED;
Resource->State = ClusterResourceOfflinePending;
goto error_exit;
}
//
// Wait 5 secs to give the holder of the address a
// chance to let go
//
Sleep(5000);
//
// Check to see if the online operation was aborted while
// this thread was blocked.
//
if (ClusWorkerCheckTerminate(pWorker)) {
status = ERROR_OPERATION_ABORTED;
Resource->State = ClusterResourceOfflinePending;
goto error_exit;
}
retried = TRUE;
}
else {
//
// Delete the failed NTE.
//
IpaDeleteNte(
&(Resource->NteContext),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
status = ERROR_CLUSTER_IPADDR_IN_USE;
ClusResLogSystemEventByKey1(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_IN_USE,
Resource->InternalPrivateProps.AddressString
);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"IP address %1!ws! is already in use on the network, status %2!u!.\n",
Resource->InternalPrivateProps.AddressString,
status
);
goto error_exit;
}
}
//
// Check to see if the online operation was aborted while this thread
// was blocked.
//
if (ClusWorkerCheckTerminate(pWorker)) {
status = ERROR_OPERATION_ABORTED;
Resource->State = ClusterResourceOfflinePending;
goto error_exit;
}
resourceStatus.CheckPoint++;
exit = (IpaSetResourceStatus)(Resource->ResourceHandle, &resourceStatus);
if ( exit == ResourceExitStateTerminate ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Online thread aborted.\n"
);
status = ERROR_OPERATION_ABORTED;
goto error_exit;
}
if (Resource->EnableNetbios) {
//
// Bind NBT to the NTE
//
status = NbtBindInterface(
Resource->NbtDeviceName,
Resource->Address,
Resource->SubnetMask
);
if (status != ERROR_SUCCESS) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Failed to bind NBT interface %1!ws! to IP address %2!ws!, status %3!u!.\n",
Resource->NbtDeviceName,
Resource->InternalPrivateProps.AddressString,
status
);
//
// Delete the failed NBT interface.
//
IpaDeleteNbtInterface(
&(Resource->NbtDeviceName),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
//
// Take the IP address offline
//
// In Windows 2000, TCP/IP ignores requests to set the address
// of an NTE if the underlying interface is disconnected.
// This can result in the same IP address being brought online
// on two different nodes. In order to workaround this bug
// in TCP/IP, we now delete the NTE during offline processing
// instead of reusing it.
//
// Note that IpaDeleteNte() invalidates the value
// of Resource->NteContext.
//
IpaDeleteNte(
&(Resource->NteContext),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
#if 0
TcpipSetNTEAddress(Resource->NteContext, 0, 0);
#endif
goto error_exit;
}
//
// Set the WINS addresses
//
status = NbtSetWinsAddrInterface(
Resource->NbtDeviceName,
localParams->NbtPrimaryWinsAddress,
localParams->NbtSecondaryWinsAddress
);
if (status != ERROR_SUCCESS) {
ClusResLogSystemEventByKeyData1(
Resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_WINS_ADDRESS_FAILED,
sizeof(status),
&status,
Resource->NbtDeviceName
);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Failed to set WINS addresses on NBT interface %1!ws!, status %2!u!.\n",
Resource->NbtDeviceName,
status
);
//
// Delete the failed NBT interface.
//
IpaDeleteNbtInterface(
&(Resource->NbtDeviceName),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
//
// Take the IP address offline
//
// In Windows 2000, TCP/IP ignores requests to set the address
// of an NTE if the underlying interface is disconnected.
// This can result in the same IP address being brought online
// on two different nodes. In order to workaround this bug
// in TCP/IP, we now delete the NTE during offline processing
// instead of reusing it.
//
// Note that IpaDeleteNte() invalidates the value
// of Resource->NteContext.
//
IpaDeleteNte(
&(Resource->NteContext),
Resource->NodeParametersKey,
Resource->ResourceHandle
);
#if 0
TcpipSetNTEAddress(Resource->NteContext, 0, 0);
#endif
goto error_exit;
}
}
//
// Tell the DNS resolver to update its list of local ip addresses.
//
// BUGBUG - The DNS resolver should do this automatically based
// on PnP events in the Whistler release. Remove this code
// after verifiying that functionality.
//
// This issue is tracked with bug 97134.
// DnsNotifyResolver(0, 0);
DnsNotifyResolverClusterIp((IP_ADDRESS)Resource->Address, TRUE);
Resource->State = ClusterResourceOnline;
resourceStatus.CheckPoint++;
resourceStatus.ResourceState = ClusterResourceOnline;
(IpaSetResourceStatus)(Resource->ResourceHandle, &resourceStatus);
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_INFORMATION,
L"IP Address %1!ws! on adapter %2!ws! online\n",
Resource->InternalPrivateProps.AddressString,
localParams->AdapterName
);
IpaReleaseResourceLock(Resource);
IpaFreeLocalParameters(&newParams);
return(ERROR_SUCCESS);
error_exit:
ASSERT(status != ERROR_SUCCESS);
if (Resource->State == ClusterResourceOfflinePending) {
IpaDoOfflineProcessing(Resource, &resourceStatus);
//
// The resource lock was released.
//
}
else {
Resource->State = ClusterResourceFailed;
resourceStatus.CheckPoint++;
resourceStatus.ResourceState = ClusterResourceFailed;
(IpaSetResourceStatus)(Resource->ResourceHandle, &resourceStatus);
IpaReleaseResourceLock(Resource);
}
IpaFreeLocalParameters(&newParams);
return(status);
} // IpaOnlineThread
DWORD
WINAPI
IpaOnline(
IN RESID Resource,
IN OUT PHANDLE EventHandle
)
/*++
Routine Description:
Online routine for IP Address resource.
Arguments:
Resource - supplies resource id to be brought online
EventHandle - supplies a pointer to a handle to signal on error.
Return Value:
ERROR_SUCCESS if successful.
ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
acquire 'ownership'.
Win32 error code if other failure.
--*/
{
PIPA_RESOURCE resource = (PIPA_RESOURCE)Resource;
DWORD status;
if (resource != NULL) {
IpaAcquireResourceLock(resource);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"Bringing resource online...\n",
Resource
);
ASSERT(resource->OnlineThread.hThread == NULL);
ASSERT(
(resource->State == ClusterResourceOffline) ||
(resource->State == ClusterResourceFailed)
);
resource->State = ClusterResourceOnlinePending;
status = ClusWorkerCreate(
&(resource->OnlineThread),
IpaOnlineThread,
resource
);
if (status != ERROR_SUCCESS) {
resource->State = ClusterResourceOffline;
(IpaLogEvent)(
resource->ResourceHandle,
LOG_ERROR,
L"Unable to start online thread, status %1!u!.\n",
status
);
} else {
status = ERROR_IO_PENDING;
}
IpaReleaseResourceLock(resource);
} else {
status = ERROR_RESOURCE_NOT_FOUND;
}
return(status);
} // IpaOnline
DWORD
IpaWorkerThread(
LPVOID Context
)
{
DWORD status;
DWORD dwFilter;
DWORD_PTR key;
DWORD event;
PIPA_RESOURCE resource;
CLUSTER_NETINTERFACE_STATE state;
HCHANGE notifyHandle;
IpaAcquireGlobalLock();
notifyHandle = IpaClusterNotifyHandle;
if (notifyHandle == NULL) {
if (!IsListEmpty(&IpaResourceList)) {
resource = CONTAINING_RECORD(
IpaResourceList.Flink,
IPA_RESOURCE,
Linkage
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_ERROR,
L"WorkerThread aborted.\n"
);
}
IpaReleaseGlobalLock();
return(ERROR_INVALID_PARAMETER);
}
if (!IsListEmpty(&IpaResourceList)) {
resource = CONTAINING_RECORD(
IpaResourceList.Flink,
IPA_RESOURCE,
Linkage
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"WorkerThread running\n"
);
}
IpaReleaseGlobalLock();
do {
status = GetClusterNotify(
notifyHandle,
&key,
&event,
NULL,
NULL,
INFINITE
);
if (status == ERROR_SUCCESS) {
if ( (event == CLUSTER_CHANGE_NETINTERFACE_STATE) ||
(event == CLUSTER_CHANGE_NETINTERFACE_DELETED)
)
{
IpaAcquireGlobalLock();
resource = IpaFindResourceInList((PVOID) key);
if (resource != NULL) {
IpaAcquireResourceLock(resource);
IpaReleaseGlobalLock();
if( (resource->State == ClusterResourceOnline) ||
(resource->State == ClusterResourceOnlinePending)
)
{
//
// Process the event.
//
if (event == CLUSTER_CHANGE_NETINTERFACE_STATE) {
resource->FailureStatus = ERROR_SUCCESS;
state = GetClusterNetInterfaceState(
resource->InterfaceHandle
);
if (state == ClusterNetInterfaceStateUnknown) {
status = GetLastError();
(IpaLogEvent)(
resource->ResourceHandle,
LOG_ERROR,
L"WorkerThread: Failed to get state for netinterface %1!ws!, status %2!u!.\n",
resource->LocalParams.InterfaceId,
status
);
}
else if ((state == ClusterNetInterfaceFailed) ||
(state == ClusterNetInterfaceUnavailable)
)
{
resource->FailureStatus = ERROR_IO_DEVICE;
(IpaLogEvent)(
resource->ResourceHandle,
LOG_WARNING,
L"WorkerThread: NetInterface %1!ws! has failed. Failing resource.\n",
resource->LocalParams.InterfaceId
);
}
else {
(IpaLogEvent)(
resource->ResourceHandle,
LOG_WARNING,
L"WorkerThread: NetInterface %1!ws! changed to state %2!u!.\n",
resource->LocalParams.InterfaceId,
state
);
}
}
else {
ASSERT(
event == CLUSTER_CHANGE_NETINTERFACE_DELETED
);
resource->FailureStatus = ERROR_DEV_NOT_EXIST;
(IpaLogEvent)(
resource->ResourceHandle,
LOG_ERROR,
L"WorkerThread: NetInterface %1!ws! was deleted. Failing resource.\n",
resource->LocalParams.InterfaceId
);
}
}
IpaReleaseResourceLock(resource);
}
else {
IpaReleaseGlobalLock();
}
}
else if (event == CLUSTER_CHANGE_HANDLE_CLOSE) {
//
// Time to exit.
//
break;
}
else {
IpaAcquireGlobalLock();
if (!IsListEmpty(&IpaResourceList)) {
resource = CONTAINING_RECORD(
IpaResourceList.Flink,
IPA_RESOURCE,
Linkage
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_WARNING,
L"WorkerThread: Received unknown event %1!u!.\n",
event
);
}
IpaReleaseGlobalLock();
ASSERT(event);
}
}
else {
IpaAcquireGlobalLock();
if (!IsListEmpty(&IpaResourceList)) {
resource = CONTAINING_RECORD(
IpaResourceList.Flink,
IPA_RESOURCE,
Linkage
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_ERROR,
L"WorkerThread: GetClusterNotify failed with status %1!u!.\n",
status
);
}
IpaReleaseGlobalLock();
break;
}
} while (status == ERROR_SUCCESS);
IpaAcquireGlobalLock();
if (!IsListEmpty(&IpaResourceList)) {
resource = CONTAINING_RECORD(
IpaResourceList.Flink,
IPA_RESOURCE,
Linkage
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"WorkerThread terminating\n"
);
}
IpaReleaseGlobalLock();
return(status);
} // IpaWorkerThread
BOOL
WINAPI
IpaInternalLooksAlive(
IN RESID Resource,
IN LPWSTR Mode
)
/*++
Routine Description:
LooksAlive routine for IP Address resource.
Arguments:
Resource - supplies the resource id to be polled.
Mode - string indicating "Looks" or "Is"
Return Value:
TRUE - Resource looks like it is alive and well
FALSE - Resource looks like it is toast.
--*/
{
PIPA_RESOURCE resource = (PIPA_RESOURCE) Resource;
BOOLEAN returnValue = TRUE;
TCPIP_NTE_INFO nteInfo;
DWORD status;
IPAddr address;
DWORD instance;
if (resource != NULL) {
IpaAcquireResourceLock(resource);
if (resource->FailureStatus == ERROR_SUCCESS) {
status = TcpipGetNTEInfo(resource->NteContext, &nteInfo);
if (status != ERROR_SUCCESS) {
returnValue = FALSE;
}
else if (nteInfo.Instance == resource->NteInstance) {
if (resource->EnableNetbios) {
status = NbtGetInterfaceInfo(
resource->NbtDeviceName,
&address,
&instance
);
if (status != ERROR_SUCCESS) {
returnValue = FALSE;
}
else if (instance != resource->NbtDeviceInstance) {
status = ERROR_DEV_NOT_EXIST;
returnValue = FALSE;
}
}
}
else {
status = ERROR_DEV_NOT_EXIST;
returnValue = FALSE;
}
}
else {
status = resource->FailureStatus;
returnValue = FALSE;
}
if (!returnValue) {
ClusResLogSystemEventByKeyData(
resource->ResourceKey,
LOG_CRITICAL,
RES_IPADDR_NTE_INTERFACE_FAILED,
sizeof(status),
&status
);
(IpaLogEvent)(
resource->ResourceHandle,
LOG_WARNING,
L"IP Interface %1!u! (address %2!ws!) failed %3!ws!Alive check, status %4!u!, address 0x%5!lx!, instance 0x%6!lx!.\n",
resource->NteContext,
resource->InternalPrivateProps.AddressString,
Mode,
status,
address,
resource->NteInstance
);
}
IpaReleaseResourceLock(resource);
}
return(returnValue);
} // IpaInternalLooksAliveCheck
BOOL
WINAPI
IpaLooksAlive(
IN RESID Resource
)
/*++
Routine Description:
LooksAlive routine for IP Address resource.
Arguments:
Resource - supplies the resource id to be polled.
Return Value:
TRUE - Resource looks like it is alive and well
FALSE - Resource looks like it is toast.
--*/
{
return(IpaInternalLooksAlive(Resource, L"Looks"));
}
BOOL
WINAPI
IpaIsAlive(
IN RESID Resource
)
/*++
Routine Description:
IsAlive routine for IP Address resource.
Arguments:
Resource - supplies the resource id to be polled.
Return Value:
TRUE - Resource is alive and well
FALSE - Resource is toast.
--*/
{
return(IpaInternalLooksAlive(Resource, L"Is"));
}
VOID
WINAPI
IpaClose(
IN RESID Resource
)
/*++
Routine Description:
Close routine for IP Address resource.
Arguments:
Resource - supplies resource id to be closed.
Return Value:
None.
--*/
{
PIPA_RESOURCE resource = (PIPA_RESOURCE)Resource;
PLIST_ENTRY entry;
TCPIP_NTE_INFO nteInfo;
DWORD status;
if (resource != NULL) {
//
// First, terminate the online thread without the lock.
//
ClusWorkerTerminate(&(resource->OnlineThread));
IpaAcquireGlobalLock();
IpaAcquireResourceLock(resource);
//
// Remove the resource from the global list
//
RemoveEntryList(&(resource->Linkage));
IpaReleaseResourceLock(resource);
IpaOpenResourceCount--;
if ((IpaOpenResourceCount == 0) && (IpaClusterHandle != NULL)) {
HCLUSTER handle = IpaClusterHandle;
IpaClusterHandle = NULL;
IpaReleaseGlobalLock();
CloseCluster(handle);
}
else {
IpaReleaseGlobalLock();
}
//
// Delete the resource's parameters
//
if (resource->NbtDeviceName != NULL) {
//
// Try to delete it.
//
IpaDeleteNbtInterface(
&(resource->NbtDeviceName),
resource->NodeParametersKey,
resource->ResourceHandle
);
}
if (resource->NteContext != INVALID_NTE_CONTEXT) {
//
// Try to delete it.
//
IpaDeleteNte(
&(resource->NteContext),
resource->NodeParametersKey,
resource->ResourceHandle
);
}
IpaFreePrivateProperties(&(resource->InternalPrivateProps));
IpaFreeLocalParameters(&(resource->LocalParams));
if (resource->ResourceKey != NULL) {
ClusterRegCloseKey(resource->ResourceKey);
}
if (resource->ParametersKey != NULL) {
ClusterRegCloseKey(resource->ParametersKey);
}
if (resource->NodeParametersKey != NULL) {
ClusterRegCloseKey(resource->NodeParametersKey);
}
if (resource->NetworksKey != NULL) {
ClusterRegCloseKey(resource->NetworksKey);
}
if (resource->InterfacesKey != NULL) {
ClusterRegCloseKey(resource->InterfacesKey);
}
DeleteCriticalSection(&(resource->Lock));
(IpaLogEvent)(
resource->ResourceHandle,
LOG_INFORMATION,
L"Resource closed.\n"
);
LocalFree(resource);
}
return;
} // IpaClose
DWORD
IpaResourceControl(
IN RESID ResourceId,
IN DWORD ControlCode,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
ResourceControl routine for Generic Application resources.
Perform the control request specified by ControlCode on the specified
resource.
Arguments:
ResourceId - Supplies the resource id for the specific resource.
ControlCode - Supplies the control code that defines the action
to be performed.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
OutBuffer - Supplies a pointer to the output buffer to be filled in.
OutBufferSize - Supplies the size, in bytes, of the available space
pointed to by OutBuffer.
BytesReturned - Returns the number of bytes of OutBuffer actually
filled in by the resource. If OutBuffer is too small, BytesReturned
contains the total number of bytes for the operation to succeed.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_FUNCTION - The requested control code is not supported.
In some cases, this allows the cluster software to perform the work.
Win32 error code - The function failed.
Notes:
We don't need to acquire the resource lock because the Cluster Service
guarantees synchronization with other APIs.
--*/
{
DWORD status;
PIPA_RESOURCE resource = (PIPA_RESOURCE) ResourceId;
DWORD resourceIndex;
DWORD required;
if ( resource == NULL ) {
DBG_PRINT( "IPAddress: ResourceControl request for a nonexistent resource id 0x%p\n",
ResourceId );
return(FALSE);
}
switch ( ControlCode ) {
case CLUSCTL_RESOURCE_UNKNOWN:
*BytesReturned = 0;
status = ERROR_SUCCESS;
break;
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
status = ResUtilGetPropertyFormats( IpaResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
status = ResUtilEnumProperties(
IpaResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required
);
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
status = IpaGetPrivateResProperties(
resource,
OutBuffer,
OutBufferSize,
BytesReturned
);
break;
case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
status = IpaValidatePrivateResProperties(
resource,
InBuffer,
InBufferSize,
NULL
);
break;
case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
status = IpaSetPrivateResProperties(
resource,
InBuffer,
InBufferSize
);
break;
default:
status = ERROR_INVALID_FUNCTION;
break;
}
return(status);
} // IpaResourceControl
DWORD
IpaResourceTypeControl(
IN LPCWSTR ResourceTypeName,
IN DWORD ControlCode,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
ResourceTypeControl routine for Generic Application resources.
Perform the control request specified by ControlCode on this resource type.
Arguments:
ResourceTypeName - Supplies the resource type name.
ControlCode - Supplies the control code that defines the action
to be performed.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
OutBuffer - Supplies a pointer to the output buffer to be filled in.
OutBufferSize - Supplies the size, in bytes, of the available space
pointed to by OutBuffer.
BytesReturned - Returns the number of bytes of OutBuffer actually
filled in by the resource. If OutBuffer is too small, BytesReturned
contains the total number of bytes for the operation to succeed.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_FUNCTION - The requested control code is not supported.
In some cases, this allows the cluster software to perform the work.
Win32 error code - The function failed.
Notes:
We don't need to acquire the resource lock because the Cluster Service
guarantees synchronization with other APIs.
--*/
{
DWORD status;
DWORD required;
switch ( ControlCode ) {
case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
*BytesReturned = 0;
status = ERROR_SUCCESS;
break;
case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
status = ResUtilGetPropertyFormats( IpaResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
status = ResUtilEnumProperties(
IpaResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required
);
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
default:
status = ERROR_INVALID_FUNCTION;
break;
}
return(status);
} // IpaResourceTypeControl
DWORD
IpaGetPrivateResProperties(
IN OUT PIPA_RESOURCE Resource,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
for resources of type IP Address.
Arguments:
Resource - Supplies the resource entry on which to operate.
OutBuffer - Returns the output data.
OutBufferSize - Supplies the size, in bytes, of the data pointed
to by OutBuffer.
BytesReturned - The number of bytes returned in OutBuffer.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
Win32 error code - The function failed.
Notes:
We don't need to acquire the resource lock because the Cluster Service
guarantees synchronization with other APIs.
--*/
{
DWORD status;
DWORD statusReturn = ERROR_SUCCESS;
DWORD required;
IPA_PRIVATE_PROPS props;
LPWSTR networkName;
LPWSTR nameOfPropInError;
ZeroMemory(&props, sizeof(props));
status = ResUtilGetPropertiesToParameterBlock(
Resource->ParametersKey,
IpaResourcePrivateProperties,
(LPBYTE) &props,
FALSE, /*CheckForRequiredProperties*/
&nameOfPropInError
);
if ( status != ERROR_SUCCESS ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unable to read the '%1' property. Error: %2!u!.\n",
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
status );
statusReturn = status;
goto error_exit;
}
//
// Find the name of the network if we read the network GUID.
//
if ( props.NetworkString != NULL ) {
networkName = IpaGetNameOfNetworkPatchGuidIfNecessary(Resource, &props);
if ( networkName == NULL ) {
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Error getting name of network whose GUID is '%1' property. Error: %2!u!.\n",
props.NetworkString,
status
);
status = ERROR_SUCCESS;
} else {
LocalFree( props.NetworkString );
props.NetworkString = networkName;
}
}
//
// Construct a property list from the parameter block.
//
status = ResUtilPropertyListFromParameterBlock(
IpaResourcePrivateProperties,
OutBuffer,
&OutBufferSize,
(LPBYTE) &props,
BytesReturned,
&required
);
//
// Add unknown properties to the property list.
//
if ( (status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA ) ) {
statusReturn = status;
status = ResUtilAddUnknownProperties(
Resource->ParametersKey,
IpaResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required
);
if ( status != ERROR_SUCCESS ) {
statusReturn = status;
}
if ( statusReturn == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
}
error_exit:
ResUtilFreeParameterBlock(
(LPBYTE) &props,
NULL,
IpaResourcePrivateProperties
);
return(statusReturn);
} // IpaGetPrivateResProperties
DWORD
IpaValidatePrivateResProperties(
IN OUT PIPA_RESOURCE Resource,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PIPA_PRIVATE_PROPS Props
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
function for resources of type IP Address.
Arguments:
Resource - Supplies the resource entry on which to operate.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
Props - Supplies the property block to fill in.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
Win32 error code - The function failed.
Notes:
We don't need to acquire the resource lock because the Cluster Service
guarantees synchronization with other APIs.
--*/
{
DWORD status;
DWORD required;
IPA_PRIVATE_PROPS currentProps;
LPWSTR networkId;
LPWSTR networkName;
LPWSTR nameOfPropInError;
IPA_PRIVATE_PROPS newProps;
PIPA_PRIVATE_PROPS pNewProps = NULL;
DWORD networkRole;
//
// Check if there is input data.
//
if ( (InBuffer == NULL) || (InBufferSize < sizeof(DWORD)) ) {
return(ERROR_INVALID_DATA);
}
//
// Capture the current set of private properties from the registry.
//
ZeroMemory(&currentProps, sizeof(currentProps));
IpaAcquireResourceLock(Resource);
status = ResUtilGetPropertiesToParameterBlock(
Resource->ParametersKey,
IpaResourcePrivateProperties,
(LPBYTE) &currentProps,
FALSE, /*CheckForRequiredProperties*/
&nameOfPropInError
);
IpaReleaseResourceLock(Resource);
if ( status != ERROR_SUCCESS ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Unable to read the '%1' property. Error: %2!u!.\n",
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
status );
goto error_exit;
}
//
// Find the name of the network if we read the network GUID.
//
if ( currentProps.NetworkString != NULL ) {
networkName = IpaGetNameOfNetworkPatchGuidIfNecessary(
Resource,
&currentProps
);
if ( networkName == NULL ) {
//
// this is not necessarily an error. Changing the network of the
// NIC on which this resource is dependent will cause the old
// network GUID in the registry to be invalid. If the user has
// specified a new network, we'll discover later on in this
// routine and get the correct GUID.
//
status = GetLastError();
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_WARNING,
L"Error getting name of network whose GUID is '%1' property. Error: %2!u!.\n",
currentProps.NetworkString,
status
);
}
LocalFree( currentProps.NetworkString );
currentProps.NetworkString = networkName;
}
//
// Duplicate the current parameter block.
//
if ( Props == NULL ) {
pNewProps = &newProps;
} else {
pNewProps = Props;
}
ZeroMemory( pNewProps, sizeof(IPA_PRIVATE_PROPS) );
status = ResUtilDupParameterBlock(
(LPBYTE) pNewProps,
(LPBYTE) &currentProps,
IpaResourcePrivateProperties
);
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
//
// Parse and validate the new properties.
//
status = ResUtilVerifyPropertyTable(
IpaResourcePrivateProperties,
NULL,
TRUE, // Allow unknowns
InBuffer,
InBufferSize,
(LPBYTE) pNewProps
);
if ( status == ERROR_SUCCESS ) {
ULONG newIpAddress = 0;
//
// Validate the parameter values.
//
if (pNewProps->NetworkString != NULL) {
//
// Get the network ID for the specified network.
//
networkId = IpaGetIdOfNetwork(
Resource,
pNewProps->NetworkString
);
if ( networkId == NULL ) {
status = GetLastError();
goto error_exit;
}
LocalFree( pNewProps->NetworkString );
pNewProps->NetworkString = networkId;
//
// Verify that the network role allows an IP address resource.
//
status = IpaGetRoleOfNetwork(
Resource,
networkId,
&networkRole
);
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
if ( networkRole != ClusterNetworkRoleClientAccess &&
networkRole != ClusterNetworkRoleInternalAndClient ) {
(IpaLogEvent)(
Resource->ResourceHandle,
LOG_ERROR,
L"Cannot set network to %1!ws! because "
L"network role (%2!u!) does not allow "
L"IP address resources.\n",
networkId,
networkRole
);
status = ERROR_CLUSTER_INVALID_NETWORK;
goto error_exit;
}
}
if (pNewProps->AddressString != NULL) {
//
// Validate the IP address.
//
ULONG nAddress;
status = ClRtlTcpipStringToAddress(
pNewProps->AddressString,
&nAddress
);
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
if ( ClRtlIsValidTcpipAddress( nAddress ) == FALSE ) {
status = ERROR_INVALID_PARAMETER;
goto error_exit;
}
newIpAddress = nAddress;
//
// if the address is changed, make sure it is not a duplicate
//
if (lstrcmpW(
pNewProps->AddressString,
currentProps.AddressString
) != 0
)
{
BOOL isDuplicate;
isDuplicate = ClRtlIsDuplicateTcpipAddress(nAddress);
if (isDuplicate) {
//
// If this isn't the address we currently have online,
// then it is a duplicate.
//
IpaAcquireResourceLock(Resource);
if (!( ((Resource->State == ClusterResourceOnlinePending)
||
(Resource->State == ClusterResourceOnline)
||
(Resource->State == ClusterResourceOfflinePending)
)
&&
(lstrcmpW(
pNewProps->AddressString,
Resource->InternalPrivateProps.AddressString
) == 0
)
)
)
{
status = ERROR_CLUSTER_IPADDR_IN_USE;
IpaReleaseResourceLock(Resource);
goto error_exit;
}
IpaReleaseResourceLock(Resource);
}
}
}
if (pNewProps->SubnetMaskString != NULL) {
//
// Validate the subnet mask.
//
ULONG nAddress;
status = ClRtlTcpipStringToAddress(
pNewProps->SubnetMaskString,
&nAddress
);
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
if ( ClRtlIsValidTcpipSubnetMask( nAddress ) == FALSE ) {
status = ERROR_INVALID_PARAMETER;
goto error_exit;
}
if (newIpAddress &&
(ClRtlIsValidTcpipAddressAndSubnetMask(newIpAddress, nAddress) == FALSE) ) {
status = ERROR_INVALID_PARAMETER;
goto error_exit;
}
}
}
error_exit:
//
// Cleanup our parameter block.
//
if (
( status != ERROR_SUCCESS && pNewProps != NULL )
||
( pNewProps == &newProps )
)
{
ResUtilFreeParameterBlock(
(LPBYTE) pNewProps,
(LPBYTE) &currentProps,
IpaResourcePrivateProperties
);
}
ResUtilFreeParameterBlock(
(LPBYTE) &currentProps,
NULL,
IpaResourcePrivateProperties
);
return(status);
} // IpaValidatePrivateResProperties
DWORD
IpaSetPrivateResProperties(
IN OUT PIPA_RESOURCE Resource,
IN PVOID InBuffer,
IN DWORD InBufferSize
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
for resources of type IP Address.
Arguments:
Resource - Supplies the resource entry on which to operate.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
Win32 error code - The function failed.
Notes:
We don't need to acquire the resource lock because the Cluster Service
guarantees synchronization with other APIs. The asynchronous OnlineThread
isn't a problem because we captured its properties during the IpaOnline
routine.
--*/
{
DWORD status;
IPA_PRIVATE_PROPS props;
ZeroMemory( &props, sizeof(IPA_PRIVATE_PROPS) );
//
// Parse the properties so they can be validated together.
// This routine does individual property validation.
//
status = IpaValidatePrivateResProperties(
Resource,
InBuffer,
InBufferSize,
&props
);
if ( status != ERROR_SUCCESS ) {
return(status);
}
IpaAcquireResourceLock(Resource);
//
// Save the parameter values.
//
status = ResUtilSetPropertyParameterBlock(
Resource->ParametersKey,
IpaResourcePrivateProperties,
NULL,
(LPBYTE) &props,
InBuffer,
InBufferSize,
NULL
);
//
// If the resource is online, return a non-success status.
//
// Note that we count on the fact that 32-bit reads are atomic.
//
if (status == ERROR_SUCCESS) {
DWORD state = Resource->State;
if ( (state == ClusterResourceOnline) ||
(state == ClusterResourceOnlinePending)
)
{
status = ERROR_RESOURCE_PROPERTIES_STORED;
} else {
status = ERROR_SUCCESS;
}
}
IpaReleaseResourceLock(Resource);
ResUtilFreeParameterBlock(
(LPBYTE) &props,
NULL,
IpaResourcePrivateProperties
);
return status;
} // IpaSetPrivateResProperties
//***********************************************************
//
// Define Function Table
//
//***********************************************************
CLRES_V1_FUNCTION_TABLE( IpAddrFunctionTable, // Name
CLRES_VERSION_V1_00, // Version
Ipa, // Prefix
NULL, // Arbitrate
NULL, // Release
IpaResourceControl, // ResControl
IpaResourceTypeControl ); // ResTypeControl