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
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(¤tProps, sizeof(currentProps));
|
|
|
|
IpaAcquireResourceLock(Resource);
|
|
|
|
status = ResUtilGetPropertiesToParameterBlock(
|
|
Resource->ParametersKey,
|
|
IpaResourcePrivateProperties,
|
|
(LPBYTE) ¤tProps,
|
|
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,
|
|
¤tProps
|
|
);
|
|
|
|
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) ¤tProps,
|
|
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) ¤tProps,
|
|
IpaResourcePrivateProperties
|
|
);
|
|
}
|
|
|
|
ResUtilFreeParameterBlock(
|
|
(LPBYTE) ¤tProps,
|
|
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
|