windows-nt/Source/XPSP1/NT/base/cluster/service/nm/interfac.c
2020-09-26 16:20:57 +08:00

7464 lines
198 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
interface.c
Abstract:
Implements the Node Manager network interface management routines.
Author:
Mike Massa (mikemas) 7-Nov-1996
Revision History:
--*/
#include "nmp.h"
#include <iphlpapi.h>
#include <iprtrmib.h>
#include <ntddndis.h>
#include <ndispnp.h>
/////////////////////////////////////////////////////////////////////////////
//
// Data
//
/////////////////////////////////////////////////////////////////////////////
#define NM_MAX_IF_PING_ENUM_SIZE 10
#define NM_MAX_UNION_PING_ENUM_SIZE 5
LIST_ENTRY NmpInterfaceList = {NULL, NULL};
LIST_ENTRY NmpDeletedInterfaceList = {NULL, NULL};
DWORD NmpInterfaceCount = 0;
WCHAR NmpUnknownString[] = L"<Unknown>";
WCHAR NmpNullString[] = L"";
RESUTIL_PROPERTY_ITEM
NmpInterfaceProperties[] =
{
{
L"Id", NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, Id)
},
{
CLUSREG_NAME_NETIFACE_NAME, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, Name)
},
{
CLUSREG_NAME_NETIFACE_DESC, NULL, CLUSPROP_FORMAT_SZ,
(DWORD_PTR) NmpNullString, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, Description)
},
{
CLUSREG_NAME_NETIFACE_NODE, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, NodeId)
},
{
CLUSREG_NAME_NETIFACE_NETWORK, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, NetworkId)
},
{
CLUSREG_NAME_NETIFACE_ADAPTER_NAME, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, AdapterName)
},
{
CLUSREG_NAME_NET_ADDRESS, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, Address)
},
{
CLUSREG_NAME_NETIFACE_ENDPOINT, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, ClusnetEndpoint)
},
{
CLUSREG_NAME_NETIFACE_STATE, NULL, CLUSPROP_FORMAT_DWORD,
0, 0, 0xFFFFFFFF,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, State)
},
{
CLUSREG_NAME_NETIFACE_ADAPTER_ID, NULL, CLUSPROP_FORMAT_SZ,
0, 0, 0,
0,
FIELD_OFFSET(NM_INTERFACE_INFO2, AdapterId)
},
{
0
}
};
/////////////////////////////////////////////////////////////////////////////
//
// Initialization & cleanup routines
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpInitializeInterfaces(
VOID
)
/*++
Routine Description:
Initializes network interface resources.
Arguments:
None.
Return Value:
A Win32 status value.
--*/
{
DWORD status;
OM_OBJECT_TYPE_INITIALIZE objectTypeInitializer;
ClRtlLogPrint(LOG_NOISE,"[NM] Initializing network interfaces.\n");
//
// Create the network interface object type
//
ZeroMemory(&objectTypeInitializer, sizeof(OM_OBJECT_TYPE_INITIALIZE));
objectTypeInitializer.ObjectSize = sizeof(NM_INTERFACE);
objectTypeInitializer.Signature = NM_INTERFACE_SIG;
objectTypeInitializer.Name = L"Network Interface";
objectTypeInitializer.DeleteObjectMethod = &NmpDestroyInterfaceObject;
status = OmCreateType(ObjectTypeNetInterface, &objectTypeInitializer);
if (status != ERROR_SUCCESS) {
WCHAR errorString[12];
wsprintfW(&(errorString[0]), L"%u", status);
CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to create network interface object type, %1!u!\n",
status
);
}
return(status);
} // NmpInitializeInterfaces
VOID
NmpCleanupInterfaces(
VOID
)
/*++
Routine Description:
Destroys all existing network interface resources.
Arguments:
None.
Return Value:
None.
--*/
{
PNM_INTERFACE netInterface;
PLIST_ENTRY entry;
DWORD status;
ClRtlLogPrint(
LOG_NOISE,
"[NM] Interface cleanup starting...\n"
);
//
// Now clean up all the interface objects.
//
NmpAcquireLock();
while (!IsListEmpty(&NmpInterfaceList)) {
entry = RemoveHeadList(&NmpInterfaceList);
netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, Linkage);
CL_ASSERT(NM_OM_INSERTED(netInterface));
NmpDeleteInterfaceObject(netInterface, FALSE);
}
NmpReleaseLock();
ClRtlLogPrint(LOG_NOISE,"[NM] Network interface cleanup complete\n");
return;
} // NmpCleanupInterfaces
/////////////////////////////////////////////////////////////////////////////
//
// Top-level routines called during network configuration
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpCreateInterface(
IN RPC_BINDING_HANDLE JoinSponsorBinding,
IN PNM_INTERFACE_INFO2 InterfaceInfo
)
/*++
Notes:
Must not be called with NM lock held.
--*/
{
DWORD status;
CL_ASSERT(InterfaceInfo->NetIndex == NmInvalidInterfaceNetIndex);
if (JoinSponsorBinding != NULL) {
//
// We are joining a cluster. Ask the sponsor to do the dirty work.
//
status = NmRpcCreateInterface2(
JoinSponsorBinding,
NmpJoinSequence,
NmLocalNodeIdString,
InterfaceInfo
);
}
else if (NmpState == NmStateOnlinePending) {
HLOCALXSACTION xaction;
//
// We are forming a cluster. Add the definition directly to the
// database. The corresponding object will be created later in
// the form process.
//
//
// Start a transaction - this must be done before acquiring the
// NM lock.
//
xaction = DmBeginLocalUpdate();
if (xaction == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to start a transaction, status %1!u!\n",
status
);
return(status);
}
status = NmpCreateInterfaceDefinition(InterfaceInfo, xaction);
//
// Complete the transaction - this must be done after releasing
// the NM lock.
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
else {
//
// We are online. This is a PnP update.
//
NmpAcquireLock();
status = NmpGlobalCreateInterface(InterfaceInfo);
NmpReleaseLock();
}
return(status);
} // NmpCreateInterface
DWORD
NmpSetInterfaceInfo(
IN RPC_BINDING_HANDLE JoinSponsorBinding,
IN PNM_INTERFACE_INFO2 InterfaceInfo
)
/*++
Notes:
Must not be called with NM lock held.
--*/
{
DWORD status;
if (JoinSponsorBinding != NULL) {
//
// We are joining a cluster. Ask the sponsor to do the dirty work.
//
status = NmRpcSetInterfaceInfo2(
JoinSponsorBinding,
NmpJoinSequence,
NmLocalNodeIdString,
InterfaceInfo
);
}
else if (NmpState == NmStateOnlinePending) {
//
// We are forming a cluster. Update the database directly.
//
HLOCALXSACTION xaction;
//
// Start a transaction - this must be done before acquiring the
// NM lock.
//
xaction = DmBeginLocalUpdate();
if (xaction == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to start a transaction, status %1!u!\n",
status
);
return(status);
}
status = NmpSetInterfaceDefinition(InterfaceInfo, xaction);
//
// Complete the transaction - this must be done after releasing
// the NM lock.
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
else {
//
// We are online. This is a PnP update.
//
NmpAcquireLock();
status = NmpGlobalSetInterfaceInfo(InterfaceInfo);
NmpReleaseLock();
}
return(status);
} // NmpSetInterfaceInfo
DWORD
NmpDeleteInterface(
IN RPC_BINDING_HANDLE JoinSponsorBinding,
IN LPWSTR InterfaceId,
IN LPWSTR NetworkId,
IN OUT PBOOLEAN NetworkDeleted
)
/*++
Notes:
Must not be called with NM lock held.
--*/
{
DWORD status;
*NetworkDeleted = FALSE;
if (JoinSponsorBinding != NULL) {
//
// We are joining a cluster. Ask the sponsor to perform the update.
//
status = NmRpcDeleteInterface(
JoinSponsorBinding,
NmpJoinSequence,
NmLocalNodeIdString,
InterfaceId,
NetworkDeleted
);
}
else if (NmpState == NmStateOnlinePending) {
//
// We are forming a cluster. Update the database directly.
//
HLOCALXSACTION xaction;
//
// Start a transaction - this must be done before acquiring the
// NM lock.
//
xaction = DmBeginLocalUpdate();
if (xaction == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to start a transaction, status %1!u!\n",
status
);
return(status);
}
//
// Delete the interface from the database.
//
status = DmLocalDeleteTree(xaction, DmNetInterfacesKey, InterfaceId);
if (status == ERROR_SUCCESS) {
PNM_INTERFACE_ENUM2 interfaceEnum = NULL;
//
// If this interface was the last one defined for the associated
// network, delete the network.
//
status = NmpEnumInterfaceDefinitions(&interfaceEnum);
if (status == ERROR_SUCCESS) {
BOOLEAN deleteNetwork = TRUE;
PNM_INTERFACE_INFO2 interfaceInfo;
DWORD i;
for (i=0; i<interfaceEnum->InterfaceCount; i++) {
interfaceInfo = &(interfaceEnum->InterfaceList[i]);
if (wcscmp(interfaceInfo->NetworkId, NetworkId) == 0) {
deleteNetwork = FALSE;
break;
}
}
if (deleteNetwork) {
status = DmLocalDeleteTree(
xaction,
DmNetworksKey,
NetworkId
);
if (status == ERROR_SUCCESS) {
*NetworkDeleted = TRUE;
}
}
ClNetFreeInterfaceEnum(interfaceEnum);
}
}
//
// Complete the transaction - this must be done after releasing
// the NM lock.
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
else {
//
// We are online. This is a PnP update.
//
NmpAcquireLock();
status = NmpGlobalDeleteInterface(
InterfaceId,
NetworkDeleted
);
NmpReleaseLock();
}
return(status);
} // NmpDeleteInterface
/////////////////////////////////////////////////////////////////////////////
//
// Remote procedures called by active member nodes
//
/////////////////////////////////////////////////////////////////////////////
error_status_t
s_NmRpcReportInterfaceConnectivity(
IN PRPC_ASYNC_STATE AsyncState,
IN handle_t IDL_handle,
IN LPWSTR InterfaceId,
IN PNM_CONNECTIVITY_VECTOR ConnectivityVector
)
{
PNM_INTERFACE netInterface;
DWORD status = ERROR_SUCCESS;
RPC_STATUS tempStatus;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)){
netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
InterfaceId
);
if (netInterface != NULL) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Received connectivity report from node %1!u! (interface %2!u!) for network %3!ws! (%4!ws!).\n",
netInterface->Node->NodeId,
netInterface->NetIndex,
OmObjectId(netInterface->Network),
OmObjectName(netInterface->Network)
);
NmpProcessInterfaceConnectivityReport(
netInterface,
ConnectivityVector
);
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Received connectivity report from unknown interface %1!ws!.\n",
InterfaceId
);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process connectivity report.\n"
);
}
NmpReleaseLock();
tempStatus = RpcAsyncCompleteCall(AsyncState, &status);
if(tempStatus != RPC_S_OK)
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] s_NmRpcReportInterfaceConnectivity(), Error Completing Async RPC call, status %1!u!\n",
tempStatus
);
return(status);
} // s_NmRpcReportInterfaceConnectivity
error_status_t
s_NmRpcGetInterfaceOnlineAddressEnum(
IN handle_t IDL_handle,
IN LPWSTR InterfaceId,
OUT PNM_ADDRESS_ENUM * OnlineAddressEnum
)
{
PNM_INTERFACE netInterface;
DWORD status = ERROR_SUCCESS;
ClRtlLogPrint(LOG_NOISE,
"[NM] Received request to get online address enum for interface %1!ws!.\n",
InterfaceId
);
*OnlineAddressEnum = NULL;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)){
netInterface = OmReferenceObjectById(ObjectTypeNetInterface, InterfaceId);
if (netInterface != NULL) {
status = NmpBuildInterfaceOnlineAddressEnum(
netInterface,
OnlineAddressEnum
);
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] GetInterfaceOnlineAddressEnum: interface %1!ws! doesn't exist.\n",
InterfaceId
);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process GetInterfaceOnlineAddressEnum request.\n"
);
}
NmpReleaseLock();
return(status);
} // s_NmRpcGetInterfaceOnlineAddressEnum
error_status_t
s_NmRpcGetInterfacePingAddressEnum(
IN handle_t IDL_handle,
IN LPWSTR InterfaceId,
IN PNM_ADDRESS_ENUM OnlineAddressEnum,
OUT PNM_ADDRESS_ENUM * PingAddressEnum
)
{
PNM_INTERFACE netInterface;
DWORD status = ERROR_SUCCESS;
ClRtlLogPrint(LOG_NOISE,
"[NM] Received request to get ping address enum for interface %1!ws!.\n",
InterfaceId
);
*PingAddressEnum = NULL;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)){
netInterface = OmReferenceObjectById(ObjectTypeNetInterface, InterfaceId);
if (netInterface != NULL) {
status = NmpBuildInterfacePingAddressEnum(
netInterface,
OnlineAddressEnum,
PingAddressEnum
);
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] GetInterfacePingAddressEnum: interface %1!ws! doesn't exist.\n",
InterfaceId
);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process GetInterfacePingAddressEnum request.\n"
);
}
NmpReleaseLock();
return(status);
} // s_NmRpcGetInterfacePingAddressEnum
//
// Note: s_NmRpcDoInterfacePing returns void rather than CallStatus
// due to a MIDL compiler error in an early beta of W2K. Since
// the CallStatus is the final parameter, the format on the
// wire is the same; however, the call works in its current
// format, so there is no point in changing it now.
//
void
s_NmRpcDoInterfacePing(
IN PRPC_ASYNC_STATE AsyncState,
IN handle_t IDL_handle,
IN LPWSTR InterfaceId,
IN PNM_ADDRESS_ENUM PingAddressEnum,
OUT BOOLEAN * PingSucceeded,
OUT error_status_t * CallStatus
)
{
PNM_INTERFACE netInterface;
DWORD status = ERROR_SUCCESS;
RPC_STATUS tempStatus;
ClRtlLogPrint(LOG_NOISE,
"[NM] Received request to ping targets for interface %1!ws!.\n",
InterfaceId
);
*PingSucceeded = FALSE;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)){
PNM_INTERFACE netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
InterfaceId
);
if (netInterface != NULL) {
PNM_NETWORK network = netInterface->Network;
if ( (network->LocalInterface == netInterface) &&
NmpIsNetworkRegistered(network)
)
{
NmpReleaseLock();
status = NmpDoInterfacePing(
netInterface,
PingAddressEnum,
PingSucceeded
);
NmpAcquireLock();
}
else {
status = ERROR_INVALID_PARAMETER;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] RpcDoInterfacePing: interface %1!ws! isn't local.\n",
InterfaceId
);
}
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] RpcDoInterfacePing: interface %1!ws! doesn't exist.\n",
InterfaceId
);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process RpcDoInterfacePing request.\n"
);
}
ClRtlLogPrint(LOG_NOISE,
"[NM] Finished pinging targets for interface %1!ws!.\n",
InterfaceId
);
NmpReleaseLock();
*CallStatus = status;
tempStatus = RpcAsyncCompleteCall(AsyncState, NULL);
if(tempStatus != RPC_S_OK)
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] s_NmRpcDoInterfacePing() Failed to complete Async RPC call, status %1!u!\n",
tempStatus
);
return;
} // s_NmRpcDoInterfacePing
/////////////////////////////////////////////////////////////////////////////
//
// Remote procedures called by joining nodes
//
/////////////////////////////////////////////////////////////////////////////
error_status_t
s_NmRpcCreateInterface(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
IN PNM_INTERFACE_INFO InterfaceInfo1
)
{
DWORD status;
NM_INTERFACE_INFO2 interfaceInfo2;
//
// Translate and call the V2.0 procedure.
//
CopyMemory(&interfaceInfo2, InterfaceInfo1, sizeof(NM_INTERFACE_INFO));
//
// The NetIndex isn't used in this call.
//
interfaceInfo2.NetIndex = NmInvalidInterfaceNetIndex;
//
// Use the unknown string for the adapter ID.
//
interfaceInfo2.AdapterId = NmpUnknownString;
status = s_NmRpcCreateInterface2(
IDL_handle,
JoinSequence,
JoinerNodeId,
&interfaceInfo2
);
return(status);
} // s_NmRpcCreateInterface
error_status_t
s_NmRpcCreateInterface2(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
IN PNM_INTERFACE_INFO2 InterfaceInfo2
)
{
DWORD status = ERROR_SUCCESS;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)) {
PNM_NODE joinerNode = NULL;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Processing request to create new interface %1!ws! for joining node.\n",
InterfaceInfo2->Id
);
if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
joinerNode = OmReferenceObjectById(
ObjectTypeNode,
JoinerNodeId
);
if (joinerNode != NULL) {
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId) &&
(NmpSponsorNodeId == NmLocalNodeId) &&
!NmpJoinAbortPending
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpJoinTimer != 0);
//
// Suspend the join timer while we are working on
// behalf of the joiner. This precludes an abort
// from occuring as well.
//
NmpJoinTimer = 0;
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] CreateInterface call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
else {
status = ERROR_CLUSTER_NODE_NOT_MEMBER;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] CreateInterface call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
JoinerNodeId
);
}
}
if (status == ERROR_SUCCESS) {
CL_ASSERT(InterfaceInfo2->NetIndex == NmInvalidInterfaceNetIndex);
//
// Just to be safe
//
InterfaceInfo2->NetIndex = NmInvalidInterfaceNetIndex;
status = NmpGlobalCreateInterface(InterfaceInfo2);
if (joinerNode != NULL) {
//
// Verify that the join is still in progress
//
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId)
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
CL_ASSERT(NmpJoinTimer == 0);
CL_ASSERT(NmpJoinAbortPending == FALSE);
if (status == ERROR_SUCCESS) {
//
// Restart the join timer.
//
NmpJoinTimer = NM_JOIN_TIMEOUT;
}
else {
//
// Abort the join
//
NmpJoinAbort(status, joinerNode);
}
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] CreateInterface call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
}
if (joinerNode != NULL) {
OmDereferenceObject(joinerNode);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Not in valid state to process CreateInterface request.\n"
);
}
NmpReleaseLock();
return(status);
} // s_NmRpcCreateInterface2
error_status_t
s_NmRpcSetInterfaceInfo(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
IN PNM_INTERFACE_INFO InterfaceInfo1
)
{
DWORD status;
NM_INTERFACE_INFO2 interfaceInfo2;
//
// Translate and call the V2.0 procedure.
//
CopyMemory(&interfaceInfo2, InterfaceInfo1, sizeof(NM_INTERFACE_INFO));
//
// The NetIndex is not used in this call.
//
interfaceInfo2.NetIndex = NmInvalidInterfaceNetIndex;
//
// Use the unknown string for the adapter ID.
//
interfaceInfo2.AdapterId = NmpUnknownString;
status = s_NmRpcSetInterfaceInfo2(
IDL_handle,
JoinSequence,
JoinerNodeId,
&interfaceInfo2
);
return(status);
} // s_NmRpcSetInterfaceInfo
error_status_t
s_NmRpcSetInterfaceInfo2(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
IN PNM_INTERFACE_INFO2 InterfaceInfo2
)
{
DWORD status = ERROR_SUCCESS;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)) {
PNM_NODE joinerNode = NULL;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Processing request to set info for interface %1!ws! for joining node.\n",
InterfaceInfo2->Id
);
if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
joinerNode = OmReferenceObjectById(
ObjectTypeNode,
JoinerNodeId
);
if (joinerNode != NULL) {
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId) &&
(NmpSponsorNodeId == NmLocalNodeId) &&
!NmpJoinAbortPending
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpJoinTimer != 0);
//
// Suspend the join timer while we are working on
// behalf of the joiner. This precludes an abort
// from occuring as well.
//
NmpJoinTimer = 0;
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] SetInterfaceInfo call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
else {
status = ERROR_CLUSTER_NODE_NOT_MEMBER;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] SetInterfaceInfo call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
JoinerNodeId
);
}
}
if (status == ERROR_SUCCESS) {
status = NmpGlobalSetInterfaceInfo(InterfaceInfo2);
if (joinerNode != NULL) {
//
// Verify that the join is still in progress
//
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId)
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
CL_ASSERT(NmpJoinTimer == 0);
CL_ASSERT(NmpJoinAbortPending == FALSE);
if (status == ERROR_SUCCESS) {
//
// Restart the join timer.
//
NmpJoinTimer = NM_JOIN_TIMEOUT;
}
else {
//
// Abort the join
//
NmpJoinAbort(status, joinerNode);
}
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] SetInterfaceInfo call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
}
if (joinerNode != NULL) {
OmDereferenceObject(joinerNode);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Not in valid state to process SetInterfaceInfo request.\n"
);
}
NmpReleaseLock();
return(status);
} // s_NmRpcSetInterfaceInfo2
error_status_t
s_NmRpcDeleteInterface(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
IN LPWSTR InterfaceId,
OUT BOOLEAN * NetworkDeleted
)
{
DWORD status = ERROR_SUCCESS;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)) {
PNM_NODE joinerNode = NULL;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Processing request to delete interface %1!ws! for joining node.\n",
InterfaceId
);
if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
joinerNode = OmReferenceObjectById(
ObjectTypeNode,
JoinerNodeId
);
if (joinerNode != NULL) {
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId) &&
(NmpSponsorNodeId == NmLocalNodeId) &&
!NmpJoinAbortPending
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpJoinTimer != 0);
//
// Suspend the join timer while we are working on
// behalf of the joiner. This precludes an abort
// from occuring as well.
//
NmpJoinTimer = 0;
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] DeleteInterface call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
else {
status = ERROR_CLUSTER_NODE_NOT_MEMBER;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] DeleteInterface call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
JoinerNodeId
);
}
}
if (status == ERROR_SUCCESS) {
status = NmpGlobalDeleteInterface(
InterfaceId,
NetworkDeleted
);
if (joinerNode != NULL) {
//
// Verify that the join is still in progress
//
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId)
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
CL_ASSERT(NmpJoinTimer == 0);
CL_ASSERT(NmpJoinAbortPending == FALSE);
if (status == ERROR_SUCCESS) {
//
// Restart the join timer.
//
NmpJoinTimer = NM_JOIN_TIMEOUT;
}
else {
//
// Abort the join
//
NmpJoinAbort(status, joinerNode);
}
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] DeleteInterface call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
}
if (joinerNode != NULL) {
OmDereferenceObject(joinerNode);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Not in valid state to process DeleteInterface request.\n"
);
}
NmpReleaseLock();
return(status);
} // s_NmRpcDeleteInterface
error_status_t
NmpEnumInterfaceDefinitionsForJoiner(
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
OUT PNM_INTERFACE_ENUM * InterfaceEnum1,
OUT PNM_INTERFACE_ENUM2 * InterfaceEnum2
)
{
DWORD status = ERROR_SUCCESS;
PNM_NODE joinerNode = NULL;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Supplying interface information to joining node.\n"
);
if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
joinerNode = OmReferenceObjectById(
ObjectTypeNode,
JoinerNodeId
);
if (joinerNode != NULL) {
if ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId) &&
(NmpSponsorNodeId == NmLocalNodeId) &&
!NmpJoinAbortPending
)
{
CL_ASSERT(joinerNode->State == ClusterNodeJoining);
CL_ASSERT(NmpJoinerUp == FALSE);
CL_ASSERT(NmpJoinTimer != 0);
//
// Suspend the join timer while we are working on
// behalf of the joiner. This precludes an abort
// from occuring as well.
//
NmpJoinTimer = 0;
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] EnumInterfaceDefinitions call for joining node %1!ws! failed because the join was aborted.\n",
JoinerNodeId
);
}
}
else {
status = ERROR_CLUSTER_NODE_NOT_MEMBER;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] EnumInterfaceDefinitions call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
JoinerNodeId
);
}
}
if (status == ERROR_SUCCESS) {
if (InterfaceEnum1 != NULL) {
status = NmpEnumInterfaceObjects1(InterfaceEnum1);
}
else {
CL_ASSERT(InterfaceEnum2 != NULL);
status = NmpEnumInterfaceObjects(InterfaceEnum2);
}
if (joinerNode != NULL) {
if (status == ERROR_SUCCESS) {
//
// Restart the join timer.
//
NmpJoinTimer = NM_JOIN_TIMEOUT;
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NMJOIN] EnumInterfaceDefinitions failed, status %1!u!.\n",
status
);
//
// Abort the join
//
NmpJoinAbort(status, joinerNode);
}
}
}
if (joinerNode != NULL) {
OmDereferenceObject(joinerNode);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Not in valid state to process EnumInterfaceDefinitions request.\n"
);
}
NmpReleaseLock();
return(status);
} // NmpEnumInterfaceDefinitionsForJoiner
error_status_t
s_NmRpcEnumInterfaceDefinitions(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
OUT PNM_INTERFACE_ENUM * InterfaceEnum1
)
{
error_status_t status;
status = NmpEnumInterfaceDefinitionsForJoiner(
JoinSequence,
JoinerNodeId,
InterfaceEnum1,
NULL
);
return(status);
} // s_NmRpcEnumInterfaceDefinitions
error_status_t
s_NmRpcEnumInterfaceDefinitions2(
IN handle_t IDL_handle,
IN DWORD JoinSequence, OPTIONAL
IN LPWSTR JoinerNodeId, OPTIONAL
OUT PNM_INTERFACE_ENUM2 * InterfaceEnum2
)
{
error_status_t status;
status = NmpEnumInterfaceDefinitionsForJoiner(
JoinSequence,
JoinerNodeId,
NULL,
InterfaceEnum2
);
return(status);
} // s_NmRpcEnumInterfaceDefinitions2
error_status_t
s_NmRpcReportJoinerInterfaceConnectivity(
IN handle_t IDL_handle,
IN DWORD JoinSequence,
IN LPWSTR JoinerNodeId,
IN LPWSTR InterfaceId,
IN PNM_CONNECTIVITY_VECTOR ConnectivityVector
)
{
DWORD status = ERROR_SUCCESS;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)){
PNM_NODE joinerNode = OmReferenceObjectById(
ObjectTypeNode,
JoinerNodeId
);
if (joinerNode != NULL) {
//
// If the node is still joining, forward the report to the
// leader. Note that reports may race with the node transitioning
// to the up state, so accept reports from up nodes as well.
//
if ( ( (JoinSequence == NmpJoinSequence) &&
(NmpJoinerNodeId == joinerNode->NodeId) &&
(NmpSponsorNodeId == NmLocalNodeId) &&
!NmpJoinAbortPending
)
||
NM_NODE_UP(joinerNode)
)
{
PNM_INTERFACE netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
InterfaceId
);
if (netInterface != NULL) {
PNM_NETWORK network = netInterface->Network;
LPCWSTR networkId = OmObjectId(network);
if (NmpLeaderNodeId == NmLocalNodeId) {
//
// This node is the leader. Process the report.
//
ClRtlLogPrint(LOG_NOISE,
"[NM] Processing connectivity report from joiner"
"node %1!ws! for network %2!ws!.\n",
JoinerNodeId,
networkId
);
NmpProcessInterfaceConnectivityReport(
netInterface,
ConnectivityVector
);
}
else {
//
// Forward the report to the leader.
//
RPC_BINDING_HANDLE binding;
ClRtlLogPrint(LOG_NOISE,
"[NM] Forwarding connectivity report from joiner "
"node %1!ws! for network %2!ws! to leader.\n",
JoinerNodeId,
networkId
);
binding = Session[NmpLeaderNodeId];
CL_ASSERT(binding != NULL);
OmReferenceObject(network);
status = NmpReportInterfaceConnectivity(
binding,
InterfaceId,
ConnectivityVector,
(LPWSTR) networkId
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to forward connectivity report "
"from joiner node %1!ws! for network %2!ws!"
"to leader, status %3!u!\n",
JoinerNodeId,
networkId,
status
);
}
OmDereferenceObject(network);
}
OmDereferenceObject(netInterface);
}
else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] Rejecting connectivity report from joining "
"node %1!ws! because interface %2!ws! does not "
"exist.\n",
JoinerNodeId,
InterfaceId
);
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
}
}
else {
status = ERROR_CLUSTER_JOIN_ABORTED;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] Ignoring connectivity report from joining "
"node %1!ws! because the join was aborted.\n",
JoinerNodeId
);
}
OmDereferenceObject(joinerNode);
}
else {
status = ERROR_CLUSTER_NODE_NOT_MEMBER;
ClRtlLogPrint(LOG_UNUSUAL,
"[NMJOIN] Ignoring connectivity report from joining node "
"%1!ws! because the joiner is not a member of the cluster.\n",
JoinerNodeId
);
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NMJOIN] Not in valid state to process connectivity report "
"from joiner node %1!ws!.\n",
JoinerNodeId
);
}
NmpReleaseLock();
return(status);
} // s_NmRpcReportJoinerInterfaceConnectivity
/////////////////////////////////////////////////////////////////////////////
//
// Routines used to make global configuration changes when the node
// is online.
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpGlobalCreateInterface(
IN PNM_INTERFACE_INFO2 InterfaceInfo
)
/*++
Notes:
Called with the NmpLock held.
--*/
{
DWORD status;
DWORD interfacePropertiesSize;
PVOID interfaceProperties;
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing global update to create interface %1!ws!.\n",
InterfaceInfo->Id
);
//
// Marshall the info structures into property lists.
//
status = NmpMarshallObjectInfo(
NmpInterfaceProperties,
InterfaceInfo,
&interfaceProperties,
&interfacePropertiesSize
);
if (status == ERROR_SUCCESS) {
NmpReleaseLock();
//
// Issue a global update
//
status = GumSendUpdateEx(
GumUpdateMembership,
NmUpdateCreateInterface,
2,
interfacePropertiesSize,
interfaceProperties,
sizeof(interfacePropertiesSize),
&interfacePropertiesSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Global update to create interface %1!ws! failed, status %2!u!.\n",
InterfaceInfo->Id,
status
);
}
MIDL_user_free(interfaceProperties);
NmpAcquireLock();
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to marshall properties for new interface %1!ws!, status %2!u!\n",
InterfaceInfo->Id,
status
);
}
return(status);
} // NmpGlobalCreateInterface
DWORD
NmpGlobalSetInterfaceInfo(
IN PNM_INTERFACE_INFO2 InterfaceInfo
)
/*++
Notes:
Called with the NmpLock held.
--*/
{
DWORD status = ERROR_SUCCESS;
DWORD interfacePropertiesSize;
PVOID interfaceProperties;
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing global update to set info for interface %1!ws!.\n",
InterfaceInfo->Id
);
//
// Marshall the info structures into property lists.
//
status = NmpMarshallObjectInfo(
NmpInterfaceProperties,
InterfaceInfo,
&interfaceProperties,
&interfacePropertiesSize
);
if (status == ERROR_SUCCESS) {
NmpReleaseLock();
//
// Issue a global update
//
status = GumSendUpdateEx(
GumUpdateMembership,
NmUpdateSetInterfaceInfo,
2,
interfacePropertiesSize,
interfaceProperties,
sizeof(interfacePropertiesSize),
&interfacePropertiesSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Global update to set properties for interface %1!ws! failed, status %2!u!.\n",
InterfaceInfo->Id,
status
);
}
MIDL_user_free(interfaceProperties);
NmpAcquireLock();
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to marshall properties for interface %1!ws!, status %2!u!\n",
InterfaceInfo->Id,
status
);
}
return(status);
} // NmpGlobalSetInterfaceInfo
DWORD
NmpGlobalDeleteInterface(
IN LPWSTR InterfaceId,
IN OUT PBOOLEAN NetworkDeleted
)
/*++
Notes:
Called with the NmpLock held.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_INTERFACE netInterface;
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing global update to delete interface %1!ws!.\n",
InterfaceId
);
//
// Find the interface object
//
netInterface = OmReferenceObjectById(ObjectTypeNetInterface, InterfaceId);
if (netInterface != NULL) {
NmpReleaseLock();
//
// Issue a global update
//
status = GumSendUpdateEx(
GumUpdateMembership,
NmUpdateDeleteInterface,
1,
(lstrlenW(InterfaceId)+1) * sizeof(WCHAR),
InterfaceId
);
NmpAcquireLock();
if (status == ERROR_SUCCESS) {
//
// Check if the network was deleted too
//
if (netInterface->Network->Flags & NM_FLAG_DELETE_PENDING) {
*NetworkDeleted = TRUE;
}
else {
*NetworkDeleted = FALSE;
}
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Global update to delete interface %1!ws! failed, status %2!u!.\n",
InterfaceId,
status
);
}
OmDereferenceObject(netInterface);
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to find interface %1!ws!.\n",
InterfaceId
);
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
}
return(status);
} // NmpGlobalDeleteInterface
/////////////////////////////////////////////////////////////////////////////
//
// Routines called by other cluster service components
//
/////////////////////////////////////////////////////////////////////////////
CLUSTER_NETINTERFACE_STATE
NmGetInterfaceState(
IN PNM_INTERFACE Interface
)
/*++
Routine Description:
Arguments:
Return Value:
Notes:
Because the caller must have a reference on the object and the
call is so simple, there is no reason to put the call through the
EnterApi/LeaveApi dance.
--*/
{
CLUSTER_NETINTERFACE_STATE state;
NmpAcquireLock();
state = Interface->State;
NmpReleaseLock();
return(state);
} // NmGetInterfaceState
DWORD
NmGetInterfaceForNodeAndNetwork(
IN LPCWSTR NodeName,
IN LPCWSTR NetworkName,
OUT LPWSTR * InterfaceName
)
/*++
Routine Description:
Returns the name of the interface which connects a specified node
to a specified network.
Arguments:
NodeName - A pointer to the unicode name of the node.
NetworkName - A pointer to the unicode name of the network.
InterfaceName - On output, contains a pointer to the unicode name of the
interface.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
--*/
{
DWORD status;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnline)) {
PNM_NODE node = OmReferenceObjectByName(ObjectTypeNode, NodeName);
if (node != NULL) {
PNM_NETWORK network = OmReferenceObjectByName(
ObjectTypeNetwork,
NetworkName
);
if (network != NULL) {
PLIST_ENTRY entry;
PNM_INTERFACE netInterface;
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
for (entry = node->InterfaceList.Flink;
entry != &(node->InterfaceList);
entry = entry->Flink
)
{
netInterface = CONTAINING_RECORD(
entry,
NM_INTERFACE,
NodeLinkage
);
if (netInterface->Network == network) {
LPCWSTR interfaceId = OmObjectName(netInterface);
DWORD nameLength = NM_WCSLEN(interfaceId);
*InterfaceName = MIDL_user_allocate(nameLength);
if (*InterfaceName != NULL) {
lstrcpyW(*InterfaceName, interfaceId);
status = ERROR_SUCCESS;
}
else {
status = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
OmDereferenceObject(network);
}
else {
status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
}
OmDereferenceObject(node);
}
else {
status = ERROR_CLUSTER_NODE_NOT_FOUND;
}
NmpLockedLeaveApi();
}
else {
status = ERROR_NODE_NOT_AVAILABLE;
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process GetInterfaceForNodeAndNetwork request.\n"
);
}
NmpReleaseLock();
return(status);
} // NmGetInterfaceForNodeAndNetwork
/////////////////////////////////////////////////////////////////////////////
//
// Handlers for global updates
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpUpdateCreateInterface(
IN BOOL IsSourceNode,
IN PVOID InterfacePropertyList,
IN LPDWORD InterfacePropertyListSize
)
/*++
Routine Description:
Global update handler for creating a new interface. The interface
definition is read from the cluster database, and a corresponding
object is instantiated. The cluster transport is also updated if
necessary.
Arguments:
IsSourceNode - Set to TRUE if this node is the source of the update.
Set to FALSE otherwise.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
This routine must not be called with the NM lock held.
--*/
{
DWORD status = ERROR_SUCCESS;
NM_INTERFACE_INFO2 interfaceInfo;
BOOLEAN lockAcquired = FALSE;
HLOCALXSACTION xaction = NULL;
PNM_INTERFACE netInterface = NULL;
if (!NmpEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process CreateInterface update.\n"
);
return(ERROR_NODE_NOT_AVAILABLE);
}
ZeroMemory(&interfaceInfo, sizeof(interfaceInfo));
//
// Unmarshall the property list.
//
status = NmpConvertPropertyListToInterfaceInfo(
InterfacePropertyList,
*InterfacePropertyListSize,
&interfaceInfo
);
if (status == ERROR_SUCCESS) {
//
// Fake missing V2 fields
//
if (interfaceInfo.AdapterId == NULL) {
interfaceInfo.AdapterId = NmpUnknownString;
}
ClRtlLogPrint(LOG_NOISE,
"[NM] Received update to create interface %1!ws!.\n",
interfaceInfo.Id
);
//
// Start a transaction - this must be done before acquiring
// the NM lock.
//
xaction = DmBeginLocalUpdate();
if (xaction != NULL) {
NmpAcquireLock(); lockAcquired = TRUE;
status = NmpCreateInterfaceDefinition(&interfaceInfo, xaction);
if (status == ERROR_SUCCESS) {
CL_NODE_ID joinerNodeId;
joinerNodeId = NmpJoinerNodeId;
NmpReleaseLock();
netInterface = NmpCreateInterfaceObject(
&interfaceInfo,
TRUE // Do retry on failure
);
NmpAcquireLock();
if (netInterface != NULL) {
//
// If a node happens to be joining right now, flag
// the fact that it is now out of synch with the
// cluster config.
//
if ( ( (joinerNodeId != ClusterInvalidNodeId) &&
(netInterface->Node->NodeId != joinerNodeId)
) ||
( (NmpJoinerNodeId != ClusterInvalidNodeId) &&
(netInterface->Node->NodeId != NmpJoinerNodeId)
)
)
{
NmpJoinerOutOfSynch = TRUE;
}
ClusterEvent(
CLUSTER_EVENT_NETINTERFACE_ADDED,
netInterface
);
}
else {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to create object for interface %1!ws!, "
"status %2!u!.\n",
interfaceInfo.Id,
status
);
}
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to write definition for interface %1!ws!, "
"status %2!u!.\n",
interfaceInfo.Id,
status
);
}
}
else {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to begin a transaction, status %1!u!\n",
status
);
}
//
// Remove faked V2 fields
//
if (interfaceInfo.AdapterId == NmpUnknownString) {
interfaceInfo.AdapterId = NULL;
}
ClNetFreeInterfaceInfo(&interfaceInfo);
}
else {
ClRtlLogPrint( LOG_CRITICAL,
"[NM] Failed to unmarshall properties for new interface, "
"status %1!u!.\n",
status
);
}
if (lockAcquired) {
NmpLockedLeaveApi();
NmpReleaseLock();
}
else {
NmpLeaveApi();
}
if (xaction != NULL) {
//
// Complete the transaction - this must be done after releasing
// the NM lock.
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
if (netInterface != NULL) {
//
// Remove the reference put on by
// NmpCreateInterfaceObject.
//
OmDereferenceObject(netInterface);
}
return(status);
} // NmpUpdateCreateInterface
DWORD
NmpUpdateSetInterfaceInfo(
IN BOOL IsSourceNode,
IN PVOID InterfacePropertyList,
IN LPDWORD InterfacePropertyListSize
)
/*++
Routine Description:
Global update handler for setting the properties of an interface.
This update is issued in response to interface property changes that
are detected internally.
Arguments:
IsSourceNode - Set to TRUE if this node is the source of the update.
Set to FALSE otherwise.
InterfacePropertyList - A pointer to a property list that encodes the
new properties for the interface. All of the
string properties must be present, except those
noted in the code below.
InterfacePropertyListSize - A pointer to a variable containing the size,
in bytes, of the property list described
by the InterfacePropertyList parameter.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status;
NM_INTERFACE_INFO2 interfaceInfo;
if (!NmpEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process SetInterfaceInfo update.\n"
);
return(ERROR_NODE_NOT_AVAILABLE);
}
//
// Unmarshall the property list so we can extract the interface ID.
//
status = NmpConvertPropertyListToInterfaceInfo(
InterfacePropertyList,
*InterfacePropertyListSize,
&interfaceInfo
);
if (status == ERROR_SUCCESS) {
PNM_INTERFACE netInterface;
ClRtlLogPrint(LOG_NOISE,
"[NM] Received update to set properties for interface %1!ws!.\n",
interfaceInfo.Id
);
//
// Fake missing V2 fields
//
if (interfaceInfo.AdapterId == NULL) {
interfaceInfo.AdapterId = NmpUnknownString;
}
//
// Find the interface object
//
netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
interfaceInfo.Id
);
if (netInterface != NULL) {
HLOCALXSACTION xaction;
//
// Begin a transaction - this must be done before acquiring the
// NM lock.
//
xaction = DmBeginLocalUpdate();
if (xaction != NULL) {
NmpAcquireLock();
//
// Process the changes
//
status = NmpLocalSetInterfaceInfo(
netInterface,
&interfaceInfo,
xaction
);
NmpReleaseLock();
//
// Complete the transaction - this must be done after
// releasing the NM lock.
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
else {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to begin a transaction, status %1!u!\n",
status
);
}
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to find interface %1!ws!.\n",
interfaceInfo.Id
);
}
//
// Remove faked V2 fields
//
if (interfaceInfo.AdapterId == NmpUnknownString) {
interfaceInfo.AdapterId = NULL;
}
ClNetFreeInterfaceInfo(&interfaceInfo);
}
else {
ClRtlLogPrint( LOG_CRITICAL,
"[NM] Failed to unmarshall properties for interface update, "
"status %1!u!.\n",
status
);
}
NmpLeaveApi();
return(status);
} // NmpUpdateSetInterfaceInfo
DWORD
NmpUpdateSetInterfaceCommonProperties(
IN BOOL IsSourceNode,
IN LPWSTR InterfaceId,
IN UCHAR * PropertyList,
IN LPDWORD PropertyListLength
)
/*++
Routine Description:
Global update handler for setting the common properties of a interface.
This update is issued in response to a property change request made
through the cluster API.
Arguments:
IsSourceNode - Set to TRUE if this node is the source of the update.
Set to FALSE otherwise.
InterfaceId - A pointer to a unicode string containing the ID of the
interface to update.
PropertyList - A pointer to a property list that encodes the
new properties for the interface. The list might contain
only a partial property set for the object.
PropertyListLength - A pointer to a variable containing the size,
in bytes, of the property list described
by the PropertyList parameter.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_INTERFACE netInterface;
if (!NmpEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process SetInterfaceCommonProperties "
"update.\n"
);
return(ERROR_NODE_NOT_AVAILABLE);
}
ClRtlLogPrint(LOG_NOISE,
"[NM] Received update to set common properties for "
"interface %1!ws!.\n",
InterfaceId
);
//
// Find the interface's object
//
netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
InterfaceId
);
if (netInterface != NULL) {
HLOCALXSACTION xaction;
//
// Begin a transaction - this must be done before acquiring the
// NM lock.
//
xaction = DmBeginLocalUpdate();
if (xaction != NULL) {
NM_INTERFACE_INFO2 interfaceInfo;
ZeroMemory(&interfaceInfo, sizeof(interfaceInfo));
NmpAcquireLock();
//
// Validate the property list and convert it to an
// interface info struct. Properties that are not present
// in the property list will be copied from the interface
// object.
//
status = NmpInterfaceValidateCommonProperties(
netInterface,
PropertyList,
*PropertyListLength,
&interfaceInfo
);
if (status == ERROR_SUCCESS) {
//
// Fake missing V2 fields
//
if (interfaceInfo.AdapterId == NULL) {
interfaceInfo.AdapterId = NmpUnknownString;
}
//
// Apply the changes
//
status = NmpLocalSetInterfaceInfo(
netInterface,
&interfaceInfo,
xaction
);
NmpReleaseLock();
//
// Remove faked V2 fields
//
if (interfaceInfo.AdapterId == NmpUnknownString) {
interfaceInfo.AdapterId = NULL;
}
ClNetFreeInterfaceInfo(&interfaceInfo);
}
else {
NmpReleaseLock();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update to set common properties for interface "
"%1!ws! failed because property list validation failed "
"with status %1!u!.\n",
InterfaceId,
status
);
}
//
// Complete the transaction - this must be done after releasing
// the NM lock.
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
else {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to begin a transaction, status %1!u!\n",
status
);
}
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to find interface %1!ws!.\n",
InterfaceId
);
}
NmpLeaveApi();
return(status);
} // NmpUpdateSetInterfaceCommonProperties
DWORD
NmpUpdateDeleteInterface(
IN BOOL IsSourceNode,
IN LPWSTR InterfaceId
)
/*++
Routine Description:
Global update handler for deleting an interface. The corresponding
object is deleted. The cluster transport is also updated if
necessary.
Arguments:
IsSourceNode - Set to TRUE if this node is the source of the update.
Set to FALSE otherwise.
InterfaceId - A pointer to a unicode string containing the ID of the
interface to delete.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status;
PNM_INTERFACE netInterface;
HLOCALXSACTION xaction;
if (!NmpEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process DeleteInterface update.\n"
);
return(ERROR_NODE_NOT_AVAILABLE);
}
ClRtlLogPrint(LOG_NOISE,
"[NM] Received update request to delete interface %1!ws!.\n",
InterfaceId
);
xaction = DmBeginLocalUpdate();
if (xaction != NULL) {
//
// Find the interface object
//
netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
InterfaceId
);
if (netInterface != NULL) {
BOOLEAN deleteNetwork = FALSE;
PNM_NETWORK network;
LPCWSTR networkId;
NmpAcquireLock();
network = netInterface->Network;
networkId = OmObjectId(network);
//
// Delete the interface definition from the database.
//
status = DmLocalDeleteTree(
xaction,
DmNetInterfacesKey,
InterfaceId
);
if (status == ERROR_SUCCESS) {
if (network->InterfaceCount == 1) {
//
// This is the last interface on the network.
// Delete the network too.
//
deleteNetwork = TRUE;
status = DmLocalDeleteTree(
xaction,
DmNetworksKey,
networkId
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to delete definition for network "
"%1!ws!, status %2!u!.\n",
networkId,
status
);
}
}
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to delete definition for interface %1!ws!, "
"status %2!u!.\n",
InterfaceId,
status
);
}
if (status == ERROR_SUCCESS) {
NmpDeleteInterfaceObject(netInterface, TRUE);
if (deleteNetwork) {
NmpDeleteNetworkObject(network, TRUE);
}
else if (NmpIsNetworkRegistered(network)) {
//
// Schedule a connectivity report.
//
NmpScheduleNetworkConnectivityReport(network);
}
//
// If a node happens to be joining right now, flag the
// fact that it is now out of synch with the cluster
// config.
//
if ( (NmpJoinerNodeId != ClusterInvalidNodeId) &&
(netInterface->Node->NodeId != NmpJoinerNodeId)
)
{
NmpJoinerOutOfSynch = TRUE;
}
}
NmpReleaseLock();
OmDereferenceObject(netInterface);
}
else {
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Unable to find interface %1!ws!.\n",
InterfaceId
);
}
//
// Complete the transaction
//
if (status == ERROR_SUCCESS) {
DmCommitLocalUpdate(xaction);
}
else {
DmAbortLocalUpdate(xaction);
}
}
else {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to begin a transaction, status %1!u!\n",
status
);
}
NmpLeaveApi();
return(status);
} // NmpUpdateDeleteInterface
/////////////////////////////////////////////////////////////////////////////
//
// Update helper routines
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpLocalSetInterfaceInfo(
IN PNM_INTERFACE Interface,
IN PNM_INTERFACE_INFO2 InterfaceInfo,
IN HLOCALXSACTION Xaction
)
/*++
Routine Description:
Arguments:
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
Called with the NmpLock held.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_NETWORK network = Interface->Network;
LPCWSTR interfaceId = OmObjectId(Interface);
HDMKEY interfaceKey = NULL;
BOOLEAN updateClusnet = FALSE;
BOOLEAN propertyChanged = FALSE;
BOOLEAN nameChanged = FALSE;
LPWSTR descString = NULL;
LPWSTR adapterNameString = NULL;
LPWSTR adapterIdString = NULL;
LPWSTR addressString = NULL;
LPWSTR endpointString = NULL;
DWORD size;
ULONG ifAddress;
//
// Open the interface's database key
//
interfaceKey = DmOpenKey(DmNetInterfacesKey, interfaceId, KEY_WRITE);
if (interfaceKey == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to open database key for interface %1!ws!, "
"status %2!u!\n",
interfaceId,
status
);
goto error_exit;
}
//
// Check if the description changed.
//
if (wcscmp(Interface->Description, InterfaceInfo->Description) != 0) {
size = NM_WCSLEN(InterfaceInfo->Description);
//
// Update the database
//
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_DESC,
REG_SZ,
(CONST BYTE *) InterfaceInfo->Description,
size
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Set of name value failed for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
goto error_exit;
}
//
// Allocate new memory resources. The object will be updated when the
// transaction commits.
//
descString = MIDL_user_allocate(size);
if (descString == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory\n");
goto error_exit;
}
wcscpy(descString, InterfaceInfo->Description);
propertyChanged = TRUE;
}
//
// Check if the adapter name changed.
//
if (wcscmp(Interface->AdapterName, InterfaceInfo->AdapterName) != 0) {
size = NM_WCSLEN(InterfaceInfo->AdapterName);
//
// Update the database
//
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_NAME,
REG_SZ,
(CONST BYTE *) InterfaceInfo->AdapterName,
size
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Set of adapter name value failed for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
goto error_exit;
}
//
// Allocate new memory resources. The object will be updated when the
// transaction commits.
//
adapterNameString = MIDL_user_allocate(size);
if (adapterNameString == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory\n");
goto error_exit;
}
wcscpy(adapterNameString, InterfaceInfo->AdapterName);
propertyChanged = TRUE;
}
//
// Check if the adapter Id changed.
//
if (wcscmp(Interface->AdapterId, InterfaceInfo->AdapterId) != 0) {
size = NM_WCSLEN(InterfaceInfo->AdapterId);
//
// Update the database
//
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_ID,
REG_SZ,
(CONST BYTE *) InterfaceInfo->AdapterId,
size
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Set of adapter Id value failed for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
goto error_exit;
}
//
// Allocate new memory resources. The object will be updated when the
// transaction commits.
//
adapterIdString = MIDL_user_allocate(size);
if (adapterIdString == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory\n");
goto error_exit;
}
wcscpy(adapterIdString, InterfaceInfo->AdapterId);
propertyChanged = TRUE;
}
//
// Check if the address changed.
//
if (wcscmp(Interface->Address, InterfaceInfo->Address) != 0) {
status = ClRtlTcpipStringToAddress(
InterfaceInfo->Address,
&ifAddress
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert interface address string %1!ws! to "
"binary, status %2!u!.\n",
InterfaceInfo->Address,
status
);
goto error_exit;
}
size = NM_WCSLEN(InterfaceInfo->Address);
//
// Update the database
//
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ADDRESS,
REG_SZ,
(CONST BYTE *) InterfaceInfo->Address,
size
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Set of address value failed for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
goto error_exit;
}
//
// Allocate new memory resources. The object will be updated when the
// transaction commits.
//
addressString = MIDL_user_allocate(size);
if (addressString == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory\n");
goto error_exit;
}
wcscpy(addressString, InterfaceInfo->Address);
updateClusnet = TRUE;
propertyChanged = TRUE;
}
//
// Check if the clusnet endpoint changed.
//
if (wcscmp(
Interface->ClusnetEndpoint,
InterfaceInfo->ClusnetEndpoint
) != 0
)
{
size = NM_WCSLEN(InterfaceInfo->ClusnetEndpoint);
//
// Update the database
//
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ENDPOINT,
REG_SZ,
(CONST BYTE *) InterfaceInfo->ClusnetEndpoint,
size
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Set of endpoint value failed for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
goto error_exit;
}
//
// Allocate new memory resources. The object will be updated when the
// transaction commits.
//
endpointString = MIDL_user_allocate(size);
if (endpointString == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory\n");
goto error_exit;
}
wcscpy(endpointString, InterfaceInfo->ClusnetEndpoint);
updateClusnet = TRUE;
propertyChanged = TRUE;
}
//
// Check if the object name changed.
//
if (wcscmp(OmObjectName(Interface), InterfaceInfo->Name) != 0) {
size = NM_WCSLEN(InterfaceInfo->Name);
//
// Update the database
//
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_NAME,
REG_SZ,
(CONST BYTE *) InterfaceInfo->Name,
size
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Set of name value failed for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
goto error_exit;
}
nameChanged = TRUE;
propertyChanged = TRUE;
}
#ifdef CLUSTER_TESTPOINT
TESTPT(TpFailNmSetInterfaceInfoAbort) {
status = 999999;
goto error_exit;
}
#endif
//
// Commit the changes
//
if (nameChanged) {
status = OmSetObjectName(Interface, InterfaceInfo->Name);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to change name for interface %1!ws!, "
"status %2!u!\n",
interfaceId,
status
);
goto error_exit;
}
}
if (descString != NULL) {
MIDL_user_free(Interface->Description);
Interface->Description = descString;
}
if (adapterNameString != NULL) {
MIDL_user_free(Interface->AdapterName);
Interface->AdapterName = adapterNameString;
}
if (adapterIdString != NULL) {
MIDL_user_free(Interface->AdapterId);
Interface->AdapterId = adapterIdString;
}
if (addressString != NULL) {
MIDL_user_free(Interface->Address);
Interface->Address = addressString;
Interface->BinaryAddress = ifAddress;
}
if (endpointString != NULL) {
MIDL_user_free(Interface->ClusnetEndpoint);
Interface->ClusnetEndpoint = endpointString;
}
//
// Update the cluster transport if this network is active and the local
// node is attached to it.
//
// This operation is not reversible. Failure is fatal for this node.
//
network = Interface->Network;
if (updateClusnet && NmpIsNetworkRegistered(network)) {
PNM_NODE node = Interface->Node;
LPCWSTR networkId = OmObjectId(network);
if (Interface == network->LocalInterface) {
//
// This is the local node's interface to the network.
// We must deregister and then re-register the entire network.
//
NmpDeregisterNetwork(network);
status = NmpRegisterNetwork(
network,
TRUE // Do retry on failure
);
}
else {
//
// This is another node's interface to the network.
// Deregister and then re-register the interface.
//
NmpDeregisterInterface(Interface);
status = NmpRegisterInterface(
Interface,
TRUE // Do retry on failure
);
}
#ifdef CLUSTER_TESTPOINT
TESTPT(TpFailNmSetInterfaceInfoHalt) {
status = 999999;
}
#endif
if (status != ERROR_SUCCESS) {
//
// This is fatal.
//
CsInconsistencyHalt(status);
}
}
if (propertyChanged) {
ClusterEvent(CLUSTER_EVENT_NETINTERFACE_PROPERTY_CHANGE, Interface);
//
// If a node happens to be joining right now, flag the fact
// that it is now out of synch with the cluster config.
//
if ( (NmpJoinerNodeId != ClusterInvalidNodeId) &&
(Interface->Node->NodeId != NmpJoinerNodeId)
)
{
NmpJoinerOutOfSynch = TRUE;
}
}
return(ERROR_SUCCESS);
error_exit:
if (descString != NULL) {
MIDL_user_free(descString);
}
if (adapterNameString != NULL) {
MIDL_user_free(adapterNameString);
}
if (adapterIdString != NULL) {
MIDL_user_free(adapterIdString);
}
if (addressString != NULL) {
MIDL_user_free(addressString);
}
if (endpointString != NULL) {
MIDL_user_free(endpointString);
}
if (interfaceKey != NULL) {
DmCloseKey(interfaceKey);
}
return(status);
} // NmpLocalSetInterfaceInfo
/////////////////////////////////////////////////////////////////////////////
//
// Database management routines
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpCreateInterfaceDefinition(
IN PNM_INTERFACE_INFO2 InterfaceInfo,
IN HLOCALXSACTION Xaction
)
/*++
Routine Description:
Creates a new network interface definition in the cluster database.
Arguments:
InterfaceInfo - A structure containing the interface's definition.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status;
HDMKEY interfaceKey = NULL;
DWORD valueLength;
DWORD disposition;
ClRtlLogPrint(LOG_NOISE,
"[NM] Creating database entry for interface %1!ws!\n",
InterfaceInfo->Id
);
CL_ASSERT(InterfaceInfo->Id != NULL);
interfaceKey = DmLocalCreateKey(
Xaction,
DmNetInterfacesKey,
InterfaceInfo->Id,
0,
KEY_WRITE,
NULL,
&disposition
);
if (interfaceKey == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to create key for interface %1!ws!, status %2!u!\n",
InterfaceInfo->Id,
status
);
return(status);
}
CL_ASSERT(disposition == REG_CREATED_NEW_KEY);
//
// Write the network ID value for this interface.
//
valueLength = NM_WCSLEN(InterfaceInfo->NetworkId);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_NETWORK,
REG_SZ,
(CONST BYTE *) InterfaceInfo->NetworkId,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Write of interface network ID failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the node ID value for this interface.
//
valueLength = NM_WCSLEN(InterfaceInfo->NodeId);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_NODE,
REG_SZ,
(CONST BYTE *) InterfaceInfo->NodeId,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Write of interface node ID failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the rest of the parameters
//
status = NmpSetInterfaceDefinition(InterfaceInfo, Xaction);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to set database definition for interface %1!ws!, status %2!u!.\n",
InterfaceInfo->Id,
status
);
}
error_exit:
if (interfaceKey != NULL) {
DmCloseKey(interfaceKey);
}
return(status);
} // NmpCreateInterfaceDefinition
DWORD
NmpGetInterfaceDefinition(
IN LPWSTR InterfaceId,
OUT PNM_INTERFACE_INFO2 InterfaceInfo
)
/*++
Routine Description:
Reads information about a defined cluster network interface from the
cluster database and fills in a structure describing it.
Arguments:
InterfaceId - A pointer to a unicode string containing the ID of the
interface to query.
InterfaceInfo - A pointer to the structure to fill in with node
information. The ID, NetworkId, and NodeId fields of the
structure must already be filled in.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status;
HDMKEY interfaceKey = NULL;
DWORD valueLength, valueSize;
CL_ASSERT(InterfaceId != NULL);
ZeroMemory(InterfaceInfo, sizeof(NM_INTERFACE_INFO2));
interfaceKey = DmOpenKey(DmNetInterfacesKey, InterfaceId, KEY_READ);
if (interfaceKey == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to open key for interface %1!ws!, status %2!u!\n",
InterfaceId,
status
);
return(status);
}
//
// Copy the ID string
//
InterfaceInfo->Id = MIDL_user_allocate(NM_WCSLEN(InterfaceId));
if (InterfaceInfo->Id == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory for interface %1!ws!.\n",
InterfaceId
);
goto error_exit;
}
wcscpy(InterfaceInfo->Id, InterfaceId);
//
// Read the Name for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_NAME,
REG_SZ,
&(InterfaceInfo->Name),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Query of network interface name failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Read the Description for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_DESC,
REG_SZ,
&(InterfaceInfo->Description),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Query of network interface description failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Read the Network ID for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_NETWORK,
REG_SZ,
&(InterfaceInfo->NetworkId),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Query of network id for interface %1!ws! failed, status %2!u!.\n",
InterfaceId,
status
);
goto error_exit;
}
//
// Read the Node ID for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_NODE,
REG_SZ,
&(InterfaceInfo->NodeId),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Query of node Id for interface %1!ws! failed, status %2!u!.\n",
InterfaceId,
status
);
goto error_exit;
}
//
// Read the adapter name value for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_NAME,
REG_SZ,
&(InterfaceInfo->AdapterName),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Query of network interface adapter name failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Read the adapter Id value for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_ID,
REG_SZ,
&(InterfaceInfo->AdapterId),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Query of network interface adapter Id failed, status %1!u!.\n",
status
);
InterfaceInfo->AdapterId = midl_user_allocate(
NM_WCSLEN(NmpUnknownString)
);
if (InterfaceInfo->AdapterId == NULL) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory for adapter Id.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
lstrcpyW(InterfaceInfo->AdapterId, NmpUnknownString);
}
//
// Read the address value for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_ADDRESS,
REG_SZ,
&(InterfaceInfo->Address),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Query of network interface address failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Read the ClusNet endpoint value for this interface.
//
valueLength = 0;
status = NmpQueryString(
interfaceKey,
CLUSREG_NAME_NETIFACE_ENDPOINT,
REG_SZ,
&(InterfaceInfo->ClusnetEndpoint),
&valueLength,
&valueSize
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Query of ClusNet endpoint value for network interface failed, status %1!u!.\n",
status
);
goto error_exit;
}
InterfaceInfo->State = ClusterNetInterfaceUnavailable;
InterfaceInfo->NetIndex = NmInvalidInterfaceNetIndex;
CL_ASSERT(status == ERROR_SUCCESS);
error_exit:
if (status != ERROR_SUCCESS) {
ClNetFreeInterfaceInfo(InterfaceInfo);
}
if (interfaceKey != NULL) {
DmCloseKey(interfaceKey);
}
return(status);
} // NmpGetInterfaceDefinition
DWORD
NmpSetInterfaceDefinition(
IN PNM_INTERFACE_INFO2 InterfaceInfo,
IN HLOCALXSACTION Xaction
)
/*++
Routine Description:
Updates information for a network interface in the cluster database.
Arguments:
InterfaceInfo - A pointer to a structure containing the
interface's definition.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status;
HDMKEY interfaceKey = NULL;
DWORD valueLength;
CL_ASSERT(InterfaceInfo->Id != NULL);
ClRtlLogPrint(LOG_NOISE,
"[NM] Setting database entry for interface %1!ws!\n",
InterfaceInfo->Id
);
interfaceKey = DmOpenKey(
DmNetInterfacesKey,
InterfaceInfo->Id,
KEY_WRITE
);
if (interfaceKey == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to open key for interface %1!ws!, status %2!u!\n",
InterfaceInfo->Id,
status
);
return(status);
}
//
// Write the name value for this interface.
//
valueLength = (wcslen(InterfaceInfo->Name) + 1) * sizeof(WCHAR);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_NAME,
REG_SZ,
(CONST BYTE *) InterfaceInfo->Name,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update of interface name failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the description value for this interface.
//
valueLength = (wcslen(InterfaceInfo->Description) + 1) * sizeof(WCHAR);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_DESC,
REG_SZ,
(CONST BYTE *) InterfaceInfo->Description,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update of interface description failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the adapter name value for this interface.
//
valueLength = (wcslen(InterfaceInfo->AdapterName) + 1) * sizeof(WCHAR);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_NAME,
REG_SZ,
(CONST BYTE *) InterfaceInfo->AdapterName,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update of interface adapter name failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the adapter Id value for this interface.
//
valueLength = (wcslen(InterfaceInfo->AdapterId) + 1) * sizeof(WCHAR);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ADAPTER_ID,
REG_SZ,
(CONST BYTE *) InterfaceInfo->AdapterId,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update of interface adapter Id failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the address value for this interface.
//
valueLength = (wcslen(InterfaceInfo->Address) + 1) * sizeof(WCHAR);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ADDRESS,
REG_SZ,
(CONST BYTE *) InterfaceInfo->Address,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update of interface address failed, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Write the ClusNet endpoint value for this interface.
//
valueLength = (wcslen(InterfaceInfo->ClusnetEndpoint) + 1) * sizeof(WCHAR);
status = DmLocalSetValue(
Xaction,
interfaceKey,
CLUSREG_NAME_NETIFACE_ENDPOINT,
REG_SZ,
(CONST BYTE *) InterfaceInfo->ClusnetEndpoint,
valueLength
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Update of interface endpoint name failed, status %1!u!.\n",
status
);
goto error_exit;
}
CL_ASSERT(status == ERROR_SUCCESS);
error_exit:
if (interfaceKey != NULL) {
DmCloseKey(interfaceKey);
}
return(status);
} // NmpSetInterfaceDefinition
DWORD
NmpEnumInterfaceDefinitions(
OUT PNM_INTERFACE_ENUM2 * InterfaceEnum
)
/*++
Routine Description:
Reads interface information from the cluster database and
fills in an enumeration structure.
Arguments:
InterfaceEnum - A pointer to the variable into which to place a
pointer to the allocated interface enumeration.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
--*/
{
DWORD status;
PNM_INTERFACE_ENUM2 interfaceEnum = NULL;
PNM_INTERFACE_INFO2 interfaceInfo;
WCHAR interfaceId[CS_NETINTERFACE_ID_LENGTH + 1];
DWORD i;
DWORD valueLength;
DWORD numInterfaces;
DWORD ignored;
FILETIME fileTime;
*InterfaceEnum = NULL;
//
// First count the number of interfaces.
//
status = DmQueryInfoKey(
DmNetInterfacesKey,
&numInterfaces,
&ignored, // MaxSubKeyLen
&ignored, // Values
&ignored, // MaxValueNameLen
&ignored, // MaxValueLen
&ignored, // lpcbSecurityDescriptor
&fileTime
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to query NetworkInterfaces key information, status %1!u!\n",
status
);
return(status);
}
if (numInterfaces == 0) {
valueLength = sizeof(NM_INTERFACE_ENUM2);
}
else {
valueLength = sizeof(NM_INTERFACE_ENUM2) +
(sizeof(NM_INTERFACE_INFO2) * (numInterfaces-1));
}
valueLength = sizeof(NM_INTERFACE_ENUM2) +
(sizeof(NM_INTERFACE_INFO2) * (numInterfaces-1));
interfaceEnum = MIDL_user_allocate(valueLength);
if (interfaceEnum == NULL) {
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory.\n");
return(ERROR_NOT_ENOUGH_MEMORY);
}
ZeroMemory(interfaceEnum, valueLength);
for (i=0; i < numInterfaces; i++) {
interfaceInfo = &(interfaceEnum->InterfaceList[i]);
valueLength = sizeof(interfaceId);
status = DmEnumKey(
DmNetInterfacesKey,
i,
&(interfaceId[0]),
&valueLength,
NULL
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to enumerate interface key, status %1!u!\n",
status
);
goto error_exit;
}
status = NmpGetInterfaceDefinition(interfaceId, interfaceInfo);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
interfaceEnum->InterfaceCount++;
}
*InterfaceEnum = interfaceEnum;
return(ERROR_SUCCESS);
error_exit:
if (interfaceEnum != NULL) {
ClNetFreeInterfaceEnum(interfaceEnum);
}
return(status);
} // NmpEnumInterfaceDefinitions
/////////////////////////////////////////////////////////////////////////////
//
// Object management routines
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpCreateInterfaceObjects(
IN PNM_INTERFACE_ENUM2 InterfaceEnum
)
/*++
Routine Description:
Processes an interface enumeration and creates interface objects.
Arguments:
InterfaceEnum - A pointer to an interface enumeration structure.
Return Value:
ERROR_SUCCESS if the routine completes successfully.
A Win32 error code otherwise.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_INTERFACE_INFO2 interfaceInfo;
PNM_INTERFACE netInterface;
DWORD i;
for (i=0; i < InterfaceEnum->InterfaceCount; i++) {
interfaceInfo = &(InterfaceEnum->InterfaceList[i]);
netInterface = NmpCreateInterfaceObject(
interfaceInfo,
FALSE // Don't retry on failure
);
if (netInterface == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to create interface %1!ws!, status %2!u!.\n",
interfaceInfo->Id,
status
);
break;
}
else {
OmDereferenceObject(netInterface);
}
}
return(status);
} // NmpCreateInterfaceObjects
PNM_INTERFACE
NmpCreateInterfaceObject(
IN PNM_INTERFACE_INFO2 InterfaceInfo,
IN BOOLEAN RetryOnFailure
)
/*++
Routine Description:
Creates an interface object.
Arguments:
InterfacInfo - A pointer to a structure containing the definition for
the interface to create.
RegisterWithClusterTransport - TRUE if this interface should be registered
with the cluster transport.
FALSE otherwise.
IssueEvent - TRUE if an INTERFACE_ADDED event should be issued when this
object is created. FALSE otherwise.
Return Value:
A pointer to the new interface object on success.
NULL on failure.
--*/
{
DWORD status;
PNM_NETWORK network = NULL;
PNM_NODE node = NULL;
PNM_INTERFACE netInterface = NULL;
BOOL created = FALSE;
PNM_CONNECTIVITY_MATRIX matrixEntry;
ClRtlLogPrint(LOG_NOISE,
"[NM] Creating object for interface %1!ws! (%2!ws!).\n",
InterfaceInfo->Id,
InterfaceInfo->Name
);
status = NmpPrepareToCreateInterface(
InterfaceInfo,
&network,
&node
);
if (status != ERROR_SUCCESS) {
SetLastError(status);
return(NULL);
}
//
// Create the interface object.
//
netInterface = OmCreateObject(
ObjectTypeNetInterface,
InterfaceInfo->Id,
InterfaceInfo->Name,
&created
);
if (netInterface == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to create object for interface %1!ws!, status %2!u!\n",
InterfaceInfo->Id,
status
);
goto error_exit;
}
CL_ASSERT(created == TRUE);
//
// Initialize the interface object.
//
ZeroMemory(netInterface, sizeof(NM_INTERFACE));
netInterface->Network = network;
netInterface->Node = node;
netInterface->State = ClusterNetInterfaceUnavailable;
netInterface->Description = MIDL_user_allocate(
NM_WCSLEN(InterfaceInfo->Description)
);
if (netInterface->Description == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory.\n"
);
goto error_exit;
}
wcscpy(netInterface->Description, InterfaceInfo->Description);
netInterface->AdapterName = MIDL_user_allocate(
(wcslen(InterfaceInfo->AdapterName) + 1) *
sizeof(WCHAR)
);
if (netInterface->AdapterName == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory.\n"
);
goto error_exit;
}
wcscpy(netInterface->AdapterName, InterfaceInfo->AdapterName);
netInterface->AdapterId = MIDL_user_allocate(
(wcslen(InterfaceInfo->AdapterId) + 1) *
sizeof(WCHAR)
);
if (netInterface->AdapterId == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory.\n"
);
goto error_exit;
}
wcscpy(netInterface->AdapterId, InterfaceInfo->AdapterId);
netInterface->Address = MIDL_user_allocate(
(wcslen(InterfaceInfo->Address) + 1) *
sizeof(WCHAR)
);
if (netInterface->Address == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory.\n"
);
goto error_exit;
}
wcscpy(netInterface->Address, InterfaceInfo->Address);
status = ClRtlTcpipStringToAddress(
InterfaceInfo->Address,
&(netInterface->BinaryAddress)
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert interface address string %1!ws! to binary, status %2!u!.\n",
InterfaceInfo->Address,
status
);
goto error_exit;
}
netInterface->ClusnetEndpoint =
MIDL_user_allocate(
(wcslen(InterfaceInfo->ClusnetEndpoint) + 1) * sizeof(WCHAR)
);
if (netInterface->ClusnetEndpoint == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory.\n"
);
goto error_exit;
}
wcscpy(netInterface->ClusnetEndpoint, InterfaceInfo->ClusnetEndpoint);
NmpAcquireLock();
//
// Assign an index into the network's connectivity vector.
//
if (InterfaceInfo->NetIndex == NmInvalidInterfaceNetIndex) {
//
// Need to pick an index for this interface. Search for a free
// entry in the network's connectivity vector.
//
DWORD i;
PNM_CONNECTIVITY_VECTOR vector = network->ConnectivityVector;
for ( i=0; i<vector->EntryCount; i++) {
if ( vector->Data[i] ==
(NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown
)
{
break;
}
}
netInterface->NetIndex = i;
ClRtlLogPrint(LOG_NOISE,
"[NM] Assigned index %1!u! to interface %2!ws!.\n",
netInterface->NetIndex,
InterfaceInfo->Id
);
}
else {
//
// Use the index that was already assigned by our peers.
//
netInterface->NetIndex = InterfaceInfo->NetIndex;
ClRtlLogPrint(LOG_NOISE,
"[NM] Using preassigned index %1!u! for interface %2!ws!.\n",
netInterface->NetIndex,
InterfaceInfo->Id
);
}
if (netInterface->NetIndex >= network->ConnectivityVector->EntryCount) {
//
// Grow the connectivity vector by the required number of entries.
//
PNM_STATE_ENTRY oldMatrixEntry, newMatrixEntry;
DWORD i;
PNM_CONNECTIVITY_VECTOR oldConnectivityVector =
network->ConnectivityVector;
PNM_CONNECTIVITY_VECTOR newConnectivityVector;
PNM_STATE_WORK_VECTOR oldStateVector = network->StateWorkVector;
PNM_STATE_WORK_VECTOR newStateVector;
PNM_CONNECTIVITY_MATRIX newMatrix;
DWORD oldVectorSize =
oldConnectivityVector->EntryCount;
DWORD newVectorSize = netInterface->NetIndex + 1;
//
// Note that one vector entry is included
// in sizeof(NM_CONNECTIVITY_VECTOR).
//
newConnectivityVector = LocalAlloc(
LMEM_FIXED,
( sizeof(NM_CONNECTIVITY_VECTOR) +
( (newVectorSize - 1) *
sizeof(NM_STATE_ENTRY)
)
));
if (newConnectivityVector == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
NmpReleaseLock();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory for connectivity vector\n"
);
goto error_exit;
}
//
// Initialize the new vector
//
newConnectivityVector->EntryCount = newVectorSize;
CopyMemory(
&(newConnectivityVector->Data[0]),
&(oldConnectivityVector->Data[0]),
oldVectorSize * sizeof(NM_STATE_ENTRY)
);
FillMemory(
&(newConnectivityVector->Data[oldVectorSize]),
(newVectorSize - oldVectorSize) * sizeof(NM_STATE_ENTRY),
(UCHAR) ClusterNetInterfaceStateUnknown
);
//
// Grow the state work vector
//
newStateVector = LocalAlloc(
LMEM_FIXED,
newVectorSize * sizeof(NM_STATE_WORK_ENTRY)
);
if (newStateVector == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
NmpReleaseLock();
LocalFree(newConnectivityVector);
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory for state work vector\n"
);
goto error_exit;
}
CopyMemory(
&(newStateVector[0]),
&(oldStateVector[0]),
oldVectorSize * sizeof(NM_STATE_WORK_ENTRY)
);
for (i=oldVectorSize; i<newVectorSize; i++) {
newStateVector[i].State =
(NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown;
}
//
// Grow the network connecivitity matrix
//
newMatrix = LocalAlloc(
LMEM_FIXED,
NM_SIZEOF_CONNECTIVITY_MATRIX(newVectorSize)
);
if (newMatrix == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
NmpReleaseLock();
LocalFree(newConnectivityVector);
LocalFree(newStateVector);
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to allocate memory for connectivity matrix\n"
);
goto error_exit;
}
//
// Initialize the new matrix
//
FillMemory(
newMatrix,
NM_SIZEOF_CONNECTIVITY_MATRIX(newVectorSize),
(UCHAR) ClusterNetInterfaceStateUnknown
);
oldMatrixEntry = network->ConnectivityMatrix;
newMatrixEntry = newMatrix;
for (i=0; i<oldVectorSize; i++) {
CopyMemory(
newMatrixEntry,
oldMatrixEntry,
oldVectorSize * sizeof(NM_STATE_ENTRY)
);
//
// Move the pointers to the next vector
//
oldMatrixEntry = NM_NEXT_CONNECTIVITY_MATRIX_ROW(
oldMatrixEntry,
oldVectorSize
);
newMatrixEntry = NM_NEXT_CONNECTIVITY_MATRIX_ROW(
newMatrixEntry,
newVectorSize
);
}
//
// Swap the pointers
//
LocalFree(network->ConnectivityVector);
network->ConnectivityVector = newConnectivityVector;
LocalFree(network->StateWorkVector);
network->StateWorkVector = newStateVector;
LocalFree(network->ConnectivityMatrix);
network->ConnectivityMatrix = newMatrix;
}
//
// Initialize the connectivity data for this interface
//
NmpSetInterfaceConnectivityData(
network,
netInterface->NetIndex,
ClusterNetInterfaceUnavailable
);
//
// Link the interface object onto the various object lists
//
InsertTailList(&(node->InterfaceList), &(netInterface->NodeLinkage));
node->InterfaceCount++;
InsertTailList(&(network->InterfaceList), &(netInterface->NetworkLinkage));
network->InterfaceCount++;
InsertTailList(&NmpInterfaceList, &(netInterface->Linkage));
NmpInterfaceCount++;
OmInsertObject(netInterface);
netInterface->Flags |= NM_FLAG_OM_INSERTED;
//
// Remember the interface for the local node.
//
if (node == NmLocalNode) {
network->LocalInterface = netInterface;
}
//
// Register with the cluster transport if needed.
//
if (NmpIsNetworkEnabledForUse(network)) {
if (node == NmLocalNode) {
//
// This is the local node. Register the network and all
// its interfaces with the cluster transport.
//
status = NmpRegisterNetwork(network, RetryOnFailure);
if (status != ERROR_SUCCESS) {
NmpReleaseLock();
goto error_exit;
}
}
else if (NmpIsNetworkRegistered(network)) {
//
// Just register this interface.
//
status = NmpRegisterInterface(netInterface, RetryOnFailure);
if (status != ERROR_SUCCESS) {
NmpReleaseLock();
goto error_exit;
}
}
}
//
// Put an additional reference on the object for the caller.
//
OmReferenceObject(netInterface);
NmpReleaseLock();
return(netInterface);
error_exit:
if (netInterface != NULL) {
NmpAcquireLock();
NmpDeleteInterfaceObject(netInterface, FALSE);
NmpReleaseLock();
}
SetLastError(status);
return(NULL);
} // NmpCreateInterfaceObject
DWORD
NmpGetInterfaceObjectInfo1(
IN PNM_INTERFACE Interface,
IN OUT PNM_INTERFACE_INFO InterfaceInfo1
)
/*++
Routine Description:
Reads information about a defined cluster network interface from the
interface object and fills in a structure describing it.
Arguments:
Interface - A pointer to the interface object to query.
InterfaceInfo - A pointer to the structure to fill in with node
information.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
Called with NmpLock held.
--*/
{
DWORD status;
NM_INTERFACE_INFO2 interfaceInfo2;
//
// Call the V2.0 routine and translate.
//
ZeroMemory(&interfaceInfo2, sizeof(interfaceInfo2));
status = NmpGetInterfaceObjectInfo(Interface, &interfaceInfo2);
if (status == ERROR_SUCCESS) {
CopyMemory(InterfaceInfo1, &interfaceInfo2, sizeof(NM_INTERFACE_INFO));
}
//
// Free the unused V2 fields
//
midl_user_free(interfaceInfo2.AdapterId);
return(status);
} // NmpGetInterfaceObjectInfo1
DWORD
NmpGetInterfaceObjectInfo(
IN PNM_INTERFACE Interface,
IN OUT PNM_INTERFACE_INFO2 InterfaceInfo
)
/*++
Routine Description:
Reads information about a defined cluster network interface from the
interface object and fills in a structure describing it.
Arguments:
Interface - A pointer to the interface object to query.
InterfaceInfo - A pointer to the structure to fill in with node
information.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
Called with NmpLock held.
--*/
{
LPWSTR tmpString = NULL;
LPWSTR interfaceId = (LPWSTR) OmObjectId(Interface);
LPWSTR interfaceName = (LPWSTR) OmObjectName(Interface);
LPWSTR nodeId = (LPWSTR) OmObjectId(Interface->Node);
LPWSTR networkId = (LPWSTR) OmObjectId(Interface->Network);
tmpString = MIDL_user_allocate(NM_WCSLEN(interfaceId));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, interfaceId);
InterfaceInfo->Id = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(interfaceName));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, interfaceName);
InterfaceInfo->Name = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(Interface->Description));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, Interface->Description);
InterfaceInfo->Description = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(nodeId));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, nodeId);
InterfaceInfo->NodeId = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(networkId));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, networkId);
InterfaceInfo->NetworkId = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(Interface->AdapterName));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, Interface->AdapterName);
InterfaceInfo->AdapterName = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(Interface->AdapterId));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, Interface->AdapterId);
InterfaceInfo->AdapterId = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(Interface->Address));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, Interface->Address);
InterfaceInfo->Address = tmpString;
tmpString = MIDL_user_allocate(NM_WCSLEN(Interface->ClusnetEndpoint));
if (tmpString == NULL) {
goto error_exit;
}
wcscpy(tmpString, Interface->ClusnetEndpoint);
InterfaceInfo->ClusnetEndpoint = tmpString;
InterfaceInfo->State = Interface->State;
InterfaceInfo->NetIndex = Interface->NetIndex;
return(ERROR_SUCCESS);
error_exit:
ClNetFreeInterfaceInfo(InterfaceInfo);
return(ERROR_NOT_ENOUGH_MEMORY);
} // NmpGetInterfaceObjectInfo2
VOID
NmpDeleteInterfaceObject(
IN PNM_INTERFACE Interface,
IN BOOLEAN IssueEvent
)
/*++
Notes:
Called with NM global lock held.
--*/
{
LPWSTR interfaceId = (LPWSTR) OmObjectId(Interface);
PNM_NETWORK network = Interface->Network;
if (NM_DELETE_PENDING(Interface)) {
CL_ASSERT(!NM_OM_INSERTED(Interface));
return;
}
ClRtlLogPrint(LOG_NOISE,
"[NM] deleting object for interface %1!ws!\n",
interfaceId
);
Interface->Flags |= NM_FLAG_DELETE_PENDING;
if (NM_OM_INSERTED(Interface)) {
//
// Remove the interface from the various object lists.
//
DWORD status = OmRemoveObject(Interface);
CL_ASSERT(status == ERROR_SUCCESS);
RemoveEntryList(&(Interface->Linkage));
CL_ASSERT(NmpInterfaceCount > 0);
NmpInterfaceCount--;
RemoveEntryList(&(Interface->NetworkLinkage));
CL_ASSERT(network->InterfaceCount > 0);
network->InterfaceCount--;
RemoveEntryList(&(Interface->NodeLinkage));
CL_ASSERT(Interface->Node->InterfaceCount > 0);
Interface->Node->InterfaceCount--;
Interface->Flags &= ~NM_FLAG_OM_INSERTED;
}
//
// Place the object on the deleted list
//
#if DBG
{
PLIST_ENTRY entry;
for ( entry = NmpDeletedInterfaceList.Flink;
entry != &NmpDeletedInterfaceList;
entry = entry->Flink
)
{
if (entry == &(Interface->Linkage)) {
break;
}
}
CL_ASSERT(entry != &(Interface->Linkage));
}
#endif DBG
InsertTailList(&NmpDeletedInterfaceList, &(Interface->Linkage));
if (network != NULL) {
if ( (Interface->Node != NULL) &&
NmpIsNetworkEnabledForUse(network)
)
{
DWORD status;
//
// Deregister the interface from the cluster transport
//
if ( (network->LocalInterface == Interface) &&
NmpIsNetworkRegistered(network)
)
{
//
// Deregister the network and all of its interfaces
//
NmpDeregisterNetwork(network);
}
else if (NmpIsInterfaceRegistered(Interface)) {
//
// Just deregister this interface
//
NmpDeregisterInterface(Interface);
}
}
//
// Invalidate the connectivity data for the interface.
//
NmpSetInterfaceConnectivityData(
network,
Interface->NetIndex,
ClusterNetInterfaceStateUnknown
);
if (network->LocalInterface == Interface) {
network->LocalInterface = NULL;
network->Flags &= ~NM_NET_IF_WORK_FLAGS;
}
//
// If this is not the last interface on the network,
// then update the network state.
//
if ((network->InterfaceCount != 0) &&
(NmpLeaderNodeId == NmLocalNodeId)) {
NmpScheduleNetworkStateRecalc(network);
}
}
if (IssueEvent) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing interface deleted event for interface %1!ws!.\n",
interfaceId
);
ClusterEvent(CLUSTER_EVENT_NETINTERFACE_DELETED, Interface);
}
//
// Remove the initial reference so the object can be destroyed.
//
OmDereferenceObject(Interface);
return;
} // NmpDeleteInterfaceObject
BOOL
NmpDestroyInterfaceObject(
PNM_INTERFACE Interface
)
{
DWORD status;
ClRtlLogPrint(LOG_NOISE,
"[NM] destroying object for interface %1!ws!\n",
(LPWSTR) OmObjectId(Interface)
);
CL_ASSERT(NM_DELETE_PENDING(Interface));
CL_ASSERT(!NM_OM_INSERTED(Interface));
//
// Remove the interface from the deleted list
//
#if DBG
{
PLIST_ENTRY entry;
for ( entry = NmpDeletedInterfaceList.Flink;
entry != &NmpDeletedInterfaceList;
entry = entry->Flink
)
{
if (entry == &(Interface->Linkage)) {
break;
}
}
CL_ASSERT(entry == &(Interface->Linkage));
}
#endif DBG
RemoveEntryList(&(Interface->Linkage));
//
// Dereference the node and network objects
//
if (Interface->Node != NULL) {
OmDereferenceObject(Interface->Node);
}
if (Interface->Network != NULL) {
OmDereferenceObject(Interface->Network);
}
//
// Free storage used by the object fields.
//
NM_FREE_OBJECT_FIELD(Interface, Description);
NM_FREE_OBJECT_FIELD(Interface, AdapterName);
NM_FREE_OBJECT_FIELD(Interface, AdapterId);
NM_FREE_OBJECT_FIELD(Interface, Address);
NM_FREE_OBJECT_FIELD(Interface, ClusnetEndpoint);
return(TRUE);
} // NmpDestroyInterfaceObject
DWORD
NmpEnumInterfaceObjects1(
OUT PNM_INTERFACE_ENUM * InterfaceEnum1
)
/*++
Routine Description:
Reads interface information for all defined cluster networks
and fills in an enumeration structure.
Arguments:
InterfaceEnum1 - A pointer to the variable into which to place a
pointer to the allocated interface enumeration.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
Called with the NmpLock held.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_INTERFACE_ENUM interfaceEnum1 = NULL;
DWORD i;
DWORD valueLength;
PLIST_ENTRY entry;
PNM_INTERFACE netInterface;
*InterfaceEnum1 = NULL;
if (NmpInterfaceCount == 0) {
valueLength = sizeof(NM_INTERFACE_ENUM);
}
else {
valueLength =
sizeof(NM_INTERFACE_ENUM) +
(sizeof(NM_INTERFACE_INFO) * (NmpInterfaceCount - 1));
}
interfaceEnum1 = MIDL_user_allocate(valueLength);
if (interfaceEnum1 == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
ZeroMemory(interfaceEnum1, valueLength);
for (entry = NmpInterfaceList.Flink, i=0;
entry != &NmpInterfaceList;
entry = entry->Flink, i++
)
{
netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, Linkage);
status = NmpGetInterfaceObjectInfo1(
netInterface,
&(interfaceEnum1->InterfaceList[i])
);
if (status != ERROR_SUCCESS) {
ClNetFreeInterfaceEnum1(interfaceEnum1);
return(status);
}
}
interfaceEnum1->InterfaceCount = NmpInterfaceCount;
*InterfaceEnum1 = interfaceEnum1;
return(ERROR_SUCCESS);
} // NmpEnumInterfaceObjects1
DWORD
NmpEnumInterfaceObjects(
OUT PNM_INTERFACE_ENUM2 * InterfaceEnum
)
/*++
Routine Description:
Reads interface information for all defined cluster networks
and fills in an enumeration structure.
Arguments:
InterfaceEnum - A pointer to the variable into which to place a
pointer to the allocated interface enumeration.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
Called with the NmpLock held.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_INTERFACE_ENUM2 interfaceEnum = NULL;
DWORD i;
DWORD valueLength;
PLIST_ENTRY entry;
PNM_INTERFACE netInterface;
*InterfaceEnum = NULL;
if (NmpInterfaceCount == 0) {
valueLength = sizeof(NM_INTERFACE_ENUM2);
}
else {
valueLength =
sizeof(NM_INTERFACE_ENUM2) +
(sizeof(NM_INTERFACE_INFO2) * (NmpInterfaceCount - 1));
}
interfaceEnum = MIDL_user_allocate(valueLength);
if (interfaceEnum == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
ZeroMemory(interfaceEnum, valueLength);
for (entry = NmpInterfaceList.Flink, i=0;
entry != &NmpInterfaceList;
entry = entry->Flink, i++
)
{
netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, Linkage);
status = NmpGetInterfaceObjectInfo(
netInterface,
&(interfaceEnum->InterfaceList[i])
);
if (status != ERROR_SUCCESS) {
ClNetFreeInterfaceEnum((PNM_INTERFACE_ENUM2) interfaceEnum);
return(status);
}
}
interfaceEnum->InterfaceCount = NmpInterfaceCount;
*InterfaceEnum = interfaceEnum;
return(ERROR_SUCCESS);
} // NmpEnumInterfaceObjects
DWORD
NmpEnumInterfaceObjectStates(
OUT PNM_INTERFACE_STATE_ENUM * InterfaceStateEnum
)
/*++
Routine Description:
Reads state information for all defined cluster network interfaces
and fills in an enumeration structure.
Arguments:
InterfaceStateEnum - A pointer to the variable into which to place a
pointer to the allocated interface enumeration.
Return Value:
ERROR_SUCCESS if the routine succeeds.
A Win32 error code otherwise.
Notes:
Called with the NmpLock held.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_INTERFACE_STATE_ENUM interfaceStateEnum = NULL;
PNM_INTERFACE_STATE_INFO interfaceStateInfo;
DWORD i;
DWORD valueLength;
PLIST_ENTRY entry;
PNM_INTERFACE netInterface;
LPWSTR interfaceId;
*InterfaceStateEnum = NULL;
if (NmpInterfaceCount == 0) {
valueLength = sizeof(NM_INTERFACE_STATE_ENUM);
}
else {
valueLength =
sizeof(NM_INTERFACE_STATE_ENUM) +
(sizeof(NM_INTERFACE_STATE_INFO) * (NmpInterfaceCount - 1));
}
interfaceStateEnum = MIDL_user_allocate(valueLength);
if (interfaceStateEnum == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
ZeroMemory(interfaceStateEnum, valueLength);
for (entry = NmpInterfaceList.Flink, i=0;
entry != &NmpInterfaceList;
entry = entry->Flink, i++
)
{
netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, Linkage);
interfaceId = (LPWSTR) OmObjectId(netInterface);
interfaceStateInfo = &(interfaceStateEnum->InterfaceList[i]);
interfaceStateInfo->State = netInterface->State;
interfaceStateInfo->Id = MIDL_user_allocate(NM_WCSLEN(interfaceId));
if (interfaceStateInfo->Id == NULL) {
NmpFreeInterfaceStateEnum(interfaceStateEnum);
return(ERROR_NOT_ENOUGH_MEMORY);
}
lstrcpyW(interfaceStateInfo->Id, interfaceId);
}
interfaceStateEnum->InterfaceCount = NmpInterfaceCount;
*InterfaceStateEnum = interfaceStateEnum;
return(ERROR_SUCCESS);
} // NmpEnumInterfaceObjectStates
/////////////////////////////////////////////////////////////////////////////
//
// State Management routines
//
/////////////////////////////////////////////////////////////////////////////
VOID
NmpSetInterfaceConnectivityData(
PNM_NETWORK Network,
DWORD InterfaceNetIndex,
CLUSTER_NETINTERFACE_STATE State
)
{
PNM_CONNECTIVITY_MATRIX matrixEntry;
Network->ConnectivityVector->Data[InterfaceNetIndex] =
(NM_STATE_ENTRY) State;
Network->StateWorkVector[InterfaceNetIndex].State =
(NM_STATE_ENTRY) State;
matrixEntry = NM_GET_CONNECTIVITY_MATRIX_ENTRY(
Network->ConnectivityMatrix,
InterfaceNetIndex,
InterfaceNetIndex,
Network->ConnectivityVector->EntryCount
);
*matrixEntry = (NM_STATE_ENTRY)State;
return;
} // NmpSetInterfaceConnectivityData
VOID
NmpReportLocalInterfaceStateEvent(
IN CL_NODE_ID NodeId,
IN CL_NETWORK_ID NetworkId,
IN DWORD NewState
)
{
PNM_INTERFACE netInterface;
NmpAcquireLock();
if (NmpLockedEnterApi(NmStateOnlinePending)){
netInterface = NmpGetInterfaceForNodeAndNetworkById(
NodeId,
NetworkId
);
if (netInterface != NULL) {
NmpProcessLocalInterfaceStateEvent(netInterface, NewState);
}
NmpLockedLeaveApi();
}
NmpReleaseLock();
return;
} // NmReportLocalInterfaceStateEvent
VOID
NmpProcessLocalInterfaceStateEvent(
IN PNM_INTERFACE Interface,
IN CLUSTER_NETINTERFACE_STATE NewState
)
/*+
Notes:
Called with the NmpLock held.
--*/
{
DWORD status;
PNM_NETWORK network = Interface->Network;
LPCWSTR interfaceId = OmObjectId(Interface);
LPCWSTR networkId = OmObjectId(network);
LPCWSTR networkName = OmObjectName(network);
PNM_NODE node = Interface->Node;
LPCWSTR nodeName = OmObjectName(node);
PNM_CONNECTIVITY_VECTOR vector = network->ConnectivityVector;
DWORD ifNetIndex = Interface->NetIndex;
//
// Filter out stale reports for dead nodes.
//
if ((node == NmLocalNode) || (node->State != ClusterNodeDown)) {
CL_ASSERT(
vector->Data[ifNetIndex] !=
(NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown
);
//
// Apply the change to the local connectivity vector.
//
vector->Data[ifNetIndex] = (NM_STATE_ENTRY) NewState;
//
// Log an event
//
switch (NewState) {
case ClusterNetInterfaceUp:
//
// A local interface is now operational, or a remote interface
// is now reachable. Schedule an immediate connectivity report,
// since this event may avert failure of resources that depend
// on the interface.
//
if (node != NmLocalNode) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Communication was (re)established with "
"interface %1!ws! (node: %2!ws!, network: %3!ws!)\n",
interfaceId,
nodeName,
networkName
);
CsLogEvent2(
LOG_NOISE,
NM_EVENT_NETINTERFACE_UP,
nodeName,
networkName
);
}
if (NmpLeaderNodeId == NmLocalNodeId) {
//
// This node is the leader. Call the handler routine
// directly.
//
NmpReportNetworkConnectivity(network);
}
else {
//
// We need to report to the leader.
// Defer to a worker thread.
//
NmpScheduleNetworkConnectivityReport(network);
}
break;
case ClusterNetInterfaceUnreachable:
//
// A remote interface is unreachable.
//
if (node != NmLocalNode) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Communication was lost with interface "
"%1!ws! (node: %2!ws!, network: %3!ws!)\n",
interfaceId,
nodeName,
networkName
);
CsLogEvent2(
LOG_UNUSUAL,
NM_EVENT_NETINTERFACE_UNREACHABLE,
nodeName,
networkName
);
}
if (NmpLeaderNodeId == NmLocalNodeId) {
//
// This node is the leader. Call the handler routine
// directly.
//
NmpReportNetworkConnectivity(network);
}
else {
//
// Schedule a delayed connectivity report in order to
// aggregate multiple failures.
//
NmpStartNetworkConnectivityReportTimer(network);
}
break;
case ClusterNetInterfaceFailed:
//
// A local interface has failed. Schedule an immediate
// connectivity report.
//
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Local interface %1!ws! on network %2!ws! "
"has failed\n",
interfaceId,
networkName
);
CsLogEvent1(
LOG_UNUSUAL,
NM_EVENT_NETINTERFACE_FAILED,
networkName
);
if (NmpLeaderNodeId == NmLocalNodeId) {
//
// This node is the leader. Call the handler routine
// directly.
//
NmpReportNetworkConnectivity(network);
}
else {
//
// We need to report to the leader. Defer to a worker thread.
//
NmpScheduleNetworkConnectivityReport(network);
}
break;
default:
break;
}
}
else {
ClRtlLogPrint(LOG_NOISE,
"[NM] Ignoring stale report from clusnet for interface %1!ws! (node: %2!ws!, network: %3!ws!).\n",
interfaceId,
nodeName,
networkName
);
}
return;
} // NmpProcessLocalInterfaceStateEvent
DWORD
NmpReportInterfaceConnectivity(
IN RPC_BINDING_HANDLE RpcBinding,
IN LPWSTR InterfaceId,
IN PNM_CONNECTIVITY_VECTOR ConnectivityVector,
IN LPWSTR NetworkId
)
/*++
Routine Description:
Sends a network connectivity report to the leader node via RPC.
Arguments:
RpcBinding - The RPC binding handle to use in the call to the leader.
InterfaceId - A pointer to a string that identifies the interface
to which the report applies.
ConnectivityVector - A pointer to the connectivity vector to be included
in the report.
NetworkId - A pointer to a string that identifies the network with
which the interface is associated.
Return Value:
A Win32 status code.
Notes:
Called with NM lock held.
Releases & reacquires NM lock during processing.
--*/
{
RPC_ASYNC_STATE rpcAsyncState;
DWORD status;
PNM_CONNECTIVITY_REPORT_CONTEXT context;
PNM_LEADER_CHANGE_WAIT_ENTRY waitEntry;
BOOL result;
ClRtlLogPrint(LOG_NOISE,
"[NM] Reporting connectivity to leader for network %1!ws!.\n",
NetworkId
);
//
// Allocate a context block for this report
//
context = LocalAlloc(
(LMEM_FIXED | LMEM_ZEROINIT),
sizeof(NM_CONNECTIVITY_REPORT_CONTEXT)
);
if (context == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate connectivity report context, "
"status %1!u!.\n",
status
);
return(status);
}
context->ConnectivityReportEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (context->ConnectivityReportEvent == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to create event for connectivity report, "
"status %1!u!\n",
status
);
goto error_exit;
}
waitEntry = &(context->LeaderChangeWaitEntry);
waitEntry->LeaderChangeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (waitEntry->LeaderChangeEvent == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to create event for connectivity report, "
"status %1!u!\n",
status
);
goto error_exit;
}
//
// Initialize the status block for the async RPC call
//
status = RpcAsyncInitializeHandle(
&rpcAsyncState,
sizeof(rpcAsyncState)
);
if (status != RPC_S_OK) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to initialize RPC status block for connectivity "
"report, status %1!u!.\n",
status
);
goto error_exit;
}
rpcAsyncState.NotificationType = RpcNotificationTypeEvent;
rpcAsyncState.u.hEvent = context->ConnectivityReportEvent;
result = ResetEvent(context->ConnectivityReportEvent);
CL_ASSERT(result != 0);
//
// Hook changes in the node leadership.
//
result = ResetEvent(waitEntry->LeaderChangeEvent);
CL_ASSERT(result != 0);
InsertTailList(&NmpLeaderChangeWaitList, &(waitEntry->Linkage));
NmpReleaseLock();
//
// Send the report to the leader
//
status = NmRpcReportInterfaceConnectivity(
&rpcAsyncState,
RpcBinding,
InterfaceId,
ConnectivityVector
);
if (status == RPC_S_OK) {
//
// The call is pending.
//
HANDLE waitHandles[2];
DWORD rpcStatus;
//
// Wait for the call to complete or a leadership change.
//
waitHandles[0] = context->ConnectivityReportEvent;
waitHandles[1] = waitEntry->LeaderChangeEvent;
status = WaitForMultipleObjects(
2,
waitHandles,
FALSE,
INFINITE
);
if (status != WAIT_OBJECT_0) {
//
// The leadership changed. Cancel the RPC call.
//
// We would also go through this path if the wait failed for
// some reason, but that really should not happen. Either way,
// we should cancel the call.
//
CL_ASSERT(status == (WAIT_OBJECT_0 + 1));
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Leadership changed. Cancelling connectivity report for "
"network %1!ws!.\n",
NetworkId
);
rpcStatus = RpcAsyncCancelCall(&rpcAsyncState, TRUE);
CL_ASSERT(rpcStatus == RPC_S_OK);
//
// Wait for the call to complete.
//
status = WaitForSingleObject(
context->ConnectivityReportEvent,
INFINITE
);
CL_ASSERT(status == WAIT_OBJECT_0);
}
//
// At this point, the call should be complete. Get the completion
// status. Any RPC error will be returned in 'rpcStatus'. If there
// was no RPC error, then any application error will be returned
// in 'status'.
//
rpcStatus = RpcAsyncCompleteCall(&rpcAsyncState, &status);
if (rpcStatus != RPC_S_OK) {
//
// Either the call was cancelled or an RPC error
// occurred. The application status is irrelevant.
//
status = rpcStatus;
}
if (status == RPC_S_OK) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Connectivity report completed successfully "
"for network %1!ws!.\n",
NetworkId
);
}
else if (status == RPC_S_CALL_CANCELLED) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Connectivity report was cancelled for "
"network %1!ws!.\n",
NetworkId
);
}
else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Connectivity report failed for network "
"%1!ws!, status %2!u!.\n",
NetworkId,
status
);
CL_ASSERT(status != RPC_S_ASYNC_CALL_PENDING);
}
}
else {
//
// A synchronous error was returned.
//
CL_ASSERT(status != RPC_S_ASYNC_CALL_PENDING);
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Connectivity report failed for network %1!ws!, "
"status %2!u!.\n",
NetworkId,
status
);
}
NmpAcquireLock();
error_exit:
//
// Free the context block
//
if (context != NULL) {
if (context->ConnectivityReportEvent != NULL) {
CloseHandle(context->ConnectivityReportEvent);
}
if (waitEntry->LeaderChangeEvent != NULL) {
//
// Remove our leadership change notification hook.
//
if (waitEntry->Linkage.Flink != NULL) {
RemoveEntryList(&(waitEntry->Linkage));
}
CloseHandle(waitEntry->LeaderChangeEvent);
}
LocalFree(context);
}
return(status);
} // NmpReportInterfaceConnectivity
VOID
NmpProcessInterfaceConnectivityReport(
IN PNM_INTERFACE SourceInterface,
IN PNM_CONNECTIVITY_VECTOR ConnectivityVector
)
/*+
Notes:
Called with NmpLock held.
--*/
{
PNM_NETWORK network = SourceInterface->Network;
PNM_CONNECTIVITY_MATRIX matrix = network->ConnectivityMatrix;
DWORD entryCount;
PNM_NODE node = SourceInterface->Node;
PNM_CONNECTIVITY_VECTOR vector = network->ConnectivityVector;
DWORD ifNetIndex = SourceInterface->NetIndex;
//
// Filter out stale reports from dead nodes and for
// disabled/deleted networks.
//
if ( ((node == NmLocalNode) || (node->State != ClusterNodeDown)) &&
NmpIsNetworkEnabledForUse(network) &&
!NM_DELETE_PENDING(network)
)
{
//
// Update the network's connectivity matrix
//
if (network->ConnectivityVector->EntryCount <= vector->EntryCount) {
entryCount = network->ConnectivityVector->EntryCount;
}
else {
//
// An interface must have been added while this
// call was in flight. Ignore the missing data.
//
entryCount = ConnectivityVector->EntryCount;
}
CopyMemory(
NM_GET_CONNECTIVITY_MATRIX_ROW(
matrix,
ifNetIndex,
entryCount
),
&(ConnectivityVector->Data[0]),
entryCount * sizeof(NM_STATE_ENTRY)
);
//
// If this is the leader node, and no NT4 nodes are in the cluster,
// schedule a state recalculation.
//
if (NmpLeaderNodeId == NmLocalNodeId) {
NmpStartNetworkStateRecalcTimer(
network,
NM_NET_STATE_RECALC_TIMEOUT
);
}
}
else {
ClRtlLogPrint(LOG_NOISE,
"[NM] Ignoring stale connectivity report from interface %1!ws!.\n",
OmObjectId(SourceInterface)
);
}
return;
} // NmpProcessInterfaceConnectivityReport
VOID
NmpFreeInterfaceStateEnum(
PNM_INTERFACE_STATE_ENUM InterfaceStateEnum
)
{
PNM_INTERFACE_STATE_INFO interfaceStateInfo;
DWORD i;
for (i=0; i<InterfaceStateEnum->InterfaceCount; i++) {
interfaceStateInfo = &(InterfaceStateEnum->InterfaceList[i]);
if (interfaceStateInfo->Id != NULL) {
MIDL_user_free(interfaceStateInfo->Id);
}
}
MIDL_user_free(InterfaceStateEnum);
return;
} // NmpFreeInterfaceStateEnum
BOOL
NmpIsAddressInAddressEnum(
ULONGLONG Address,
PNM_ADDRESS_ENUM AddressEnum
)
{
DWORD i;
for (i=0; i<AddressEnum->AddressCount; i++) {
if (AddressEnum->AddressList[i] == Address) {
return(TRUE);
}
}
return(FALSE);
} // NmpIsAddressInAddressEnum
DWORD
NmpBuildInterfaceOnlineAddressEnum(
PNM_INTERFACE Interface,
PNM_ADDRESS_ENUM * OnlineAddressEnum
)
/*++
Called with NmpLock held and Interface referenced.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_ADDRESS_ENUM onlineAddressEnum = NULL;
DWORD onlineAddressEnumSize;
PCLRTL_NET_ADAPTER_ENUM adapterEnum = NULL;
PCLRTL_NET_ADAPTER_INFO adapterInfo = NULL;
PCLRTL_NET_INTERFACE_INFO adapterIfInfo = NULL;
PNM_ADDRESS_ENUM onlineEnum = NULL;
DWORD onlineEnumSize;
*OnlineAddressEnum = NULL;
//
// Get the local network configuration.
//
adapterEnum = ClRtlEnumNetAdapters();
if (adapterEnum == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to obtain local network configuration, status %1!u!.\n",
status
);
return(status);
}
//
// Find the adapter for this interface
//
adapterInfo = ClRtlFindNetAdapterById(
adapterEnum,
Interface->AdapterId
);
if (adapterInfo == NULL) {
status = ERROR_NOT_FOUND;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to find adapter for interface %1!ws!, status %2!u!.\n",
status
);
goto error_exit;
}
//
// Allocate an address enum structure.
//
if (adapterInfo->InterfaceCount == 0) {
onlineEnumSize = sizeof(NM_ADDRESS_ENUM);
}
else {
onlineEnumSize = sizeof(NM_ADDRESS_ENUM) +
( (adapterInfo->InterfaceCount - 1) *
sizeof(ULONGLONG)
);
}
onlineEnum = midl_user_allocate(onlineEnumSize);
if (onlineEnum == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for ping list.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
onlineEnum->AddressSize = sizeof(ULONG);
onlineEnum->AddressCount = 0;
for (adapterIfInfo = adapterInfo->InterfaceList;
adapterIfInfo != NULL;
adapterIfInfo = adapterIfInfo->Next
)
{
//
// Skip invalid addresses (0.0.0.0)
//
if (adapterIfInfo->InterfaceAddress != 0) {
onlineEnum->AddressList[onlineEnum->AddressCount++] =
(ULONGLONG) adapterIfInfo->InterfaceAddress;
ClRtlLogPrint(LOG_NOISE,
"[NM] Found address %1!ws! for interface %2!ws!.\n",
adapterIfInfo->InterfaceAddressString,
OmObjectId(Interface)
);
}
}
*OnlineAddressEnum = onlineEnum;
status = ERROR_SUCCESS;
error_exit:
if (adapterEnum != NULL) {
ClRtlFreeNetAdapterEnum(adapterEnum);
}
return(status);
} // NmpBuildInterfaceOnlineAddressEnum
DWORD
NmpBuildInterfacePingAddressEnum(
IN PNM_INTERFACE Interface,
IN PNM_ADDRESS_ENUM OnlineAddressEnum,
OUT PNM_ADDRESS_ENUM * PingAddressEnum
)
/*++
Called with NmpLock held and Interface referenced.
--*/
{
DWORD status = ERROR_SUCCESS;
PNM_NETWORK network = Interface->Network;
PMIB_IPFORWARDTABLE ipForwardTable = NULL;
PMIB_IPFORWARDROW ipRow, ipRowLimit;
PMIB_TCPTABLE tcpTable = NULL;
PMIB_TCPROW tcpRow, tcpRowLimit;
ULONG netAddress, netMask;
DWORD allocSize, tableSize;
BOOL duplicate;
DWORD i;
PNM_ADDRESS_ENUM pingEnum = NULL;
DWORD pingEnumSize;
*PingAddressEnum = NULL;
//
// Convert the network address & mask strings to binary
//
status = ClRtlTcpipStringToAddress(network->Address, &netAddress);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert network address string %1!ws! to binary, status %2!u!.\n",
network->Address,
status
);
return(status);
}
status = ClRtlTcpipStringToAddress(network->AddressMask, &netMask);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert network address mask string %1!ws! to binary, status %2!u!.\n",
network->AddressMask,
status
);
return(status);
}
//
// We don't need the lock for the rest of the function.
//
NmpReleaseLock();
//
// Allocate a ping enum structure
//
pingEnumSize = sizeof(NM_ADDRESS_ENUM) +
((NM_MAX_IF_PING_ENUM_SIZE - 1) * sizeof(ULONGLONG));
pingEnum = midl_user_allocate(pingEnumSize);
if (pingEnum == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for ping list.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
pingEnum->AddressSize = sizeof(ULONG);
pingEnum->AddressCount = 0;
//
// Fetch the IP Route Table
//
allocSize = sizeof(MIB_IPFORWARDTABLE) + (sizeof(MIB_IPFORWARDROW) * 20);
do {
if (ipForwardTable != NULL) {
LocalFree(ipForwardTable);
}
ipForwardTable = LocalAlloc(LMEM_FIXED, allocSize);
if (ipForwardTable == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for IP route table.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
tableSize = allocSize;
status = GetIpForwardTable(
ipForwardTable,
&tableSize,
FALSE
);
allocSize = tableSize;
} while (status == ERROR_INSUFFICIENT_BUFFER);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[ClNet] Failed to obtain IP route table, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Add the IP route entries to the ping list.
//
for ( ipRow = &(ipForwardTable->table[0]),
ipRowLimit = ipRow + ipForwardTable->dwNumEntries;
ipRow < ipRowLimit;
ipRow++
)
{
if ((ipRow->dwForwardNextHop & netMask) == netAddress) {
//
// Make sure this address isn't in the online address enum.
//
duplicate = NmpIsAddressInAddressEnum(
(ULONGLONG) ipRow->dwForwardNextHop,
OnlineAddressEnum
);
if (!duplicate) {
//
// Make sure this address isn't already in the ping enum.
//
duplicate = NmpIsAddressInAddressEnum(
(ULONGLONG) ipRow->dwForwardNextHop,
pingEnum
);
if (!duplicate) {
pingEnum->AddressList[pingEnum->AddressCount++] =
(ULONGLONG) ipRow->dwForwardNextHop;
if (pingEnum->AddressCount == NM_MAX_IF_PING_ENUM_SIZE) {
LocalFree(ipForwardTable);
*PingAddressEnum = pingEnum;
NmpAcquireLock();
return(ERROR_SUCCESS);
}
}
}
}
}
LocalFree(ipForwardTable); ipForwardTable = NULL;
//
// Fetch the TCP Connection Table
//
allocSize = sizeof(MIB_TCPTABLE) + (sizeof(MIB_TCPROW) * 20);
do {
if (tcpTable != NULL) {
LocalFree(tcpTable);
}
tcpTable = LocalAlloc(LMEM_FIXED, allocSize);
if (tcpTable == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for TCP conn table.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
tableSize = allocSize;
status = GetTcpTable(
tcpTable,
&tableSize,
FALSE
);
allocSize = tableSize;
} while (status == ERROR_INSUFFICIENT_BUFFER);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[ClNet] Failed to obtain TCP conn table, status %1!u!.\n",
status
);
goto error_exit;
}
//
// Add the TCP remote addresses to the ping list.
//
for ( tcpRow = &(tcpTable->table[0]),
tcpRowLimit = tcpRow + tcpTable->dwNumEntries;
tcpRow < tcpRowLimit;
tcpRow++
)
{
if ((tcpRow->dwRemoteAddr & netMask) == netAddress) {
//
// Make sure this address isn't in the online address enum.
//
duplicate = NmpIsAddressInAddressEnum(
(ULONGLONG) tcpRow->dwRemoteAddr,
OnlineAddressEnum
);
if (!duplicate) {
//
// Make sure this address isn't already in the ping enum.
//
duplicate = NmpIsAddressInAddressEnum(
(ULONGLONG) tcpRow->dwRemoteAddr,
pingEnum
);
if (!duplicate) {
pingEnum->AddressList[pingEnum->AddressCount++] =
(ULONGLONG) tcpRow->dwRemoteAddr;
if (pingEnum->AddressCount == NM_MAX_IF_PING_ENUM_SIZE) {
break;
}
}
}
}
}
*PingAddressEnum = pingEnum; pingEnum = NULL;
error_exit:
if (pingEnum != NULL) {
midl_user_free(pingEnum);
}
if (ipForwardTable != NULL) {
LocalFree(ipForwardTable);
}
if (tcpTable != NULL) {
LocalFree(tcpTable);
}
NmpAcquireLock();
return(status);
} // NmpBuildInterfacePingAddressEnum
NmpGetInterfaceOnlineAddressEnum(
PNM_INTERFACE Interface,
PNM_ADDRESS_ENUM * OnlineAddressEnum
)
/*++
Notes:
Called with NmpLock held and Interface referenced. Releases and
reacquires NmpLock.
--*/
{
DWORD status;
LPCWSTR interfaceId = OmObjectId(Interface);
PNM_NODE node = Interface->Node;
RPC_BINDING_HANDLE rpcBinding = node->IsolateRpcBinding;
if (node == NmLocalNode) {
//
// Call the internal routine directly
//
status = NmpBuildInterfaceOnlineAddressEnum(
Interface,
OnlineAddressEnum
);
}
else {
OmReferenceObject(node);
NmpReleaseLock();
CL_ASSERT(rpcBinding != NULL);
NmStartRpc(node->NodeId);
status = NmRpcGetInterfaceOnlineAddressEnum(
rpcBinding,
(LPWSTR) interfaceId,
OnlineAddressEnum
);
NmEndRpc(node->NodeId);
if(status != RPC_S_OK) {
NmDumpRpcExtErrorInfo(status);
}
NmpAcquireLock();
OmDereferenceObject(node);
}
if (status == ERROR_SUCCESS) {
if ((*OnlineAddressEnum)->AddressSize != sizeof(ULONG)) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Online enum address size is invalid for interface %1!ws!\n",
interfaceId
);
status = ERROR_INCORRECT_ADDRESS;
midl_user_free(*OnlineAddressEnum);
*OnlineAddressEnum = NULL;
}
else {
ClRtlLogPrint(LOG_NOISE,
"[NM] Online enum for interface %1!ws! contains %2!u! addresses\n",
interfaceId,
(*OnlineAddressEnum)->AddressCount
);
}
}
else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to get online address enum for interface %1!ws!, status %2!u!\n",
interfaceId,
status
);
}
return(status);
} // NmpGetInterfaceOnlineAddressEnum
NmpGetInterfacePingAddressEnum(
PNM_INTERFACE Interface,
PNM_ADDRESS_ENUM OnlineAddressEnum,
PNM_ADDRESS_ENUM * PingAddressEnum
)
/*++
Notes:
Called with NmpLock held and Interface referenced. Releases and
reacquires NmpLock.
--*/
{
DWORD status;
LPCWSTR interfaceId = OmObjectId(Interface);
PNM_NODE node = Interface->Node;
RPC_BINDING_HANDLE rpcBinding = node->IsolateRpcBinding;
if (node == NmLocalNode) {
//
// Call the internal routine directly
//
status = NmpBuildInterfacePingAddressEnum(
Interface,
OnlineAddressEnum,
PingAddressEnum
);
}
else {
OmReferenceObject(node);
NmpReleaseLock();
CL_ASSERT(rpcBinding != NULL);
NmStartRpc(node->NodeId);
status = NmRpcGetInterfacePingAddressEnum(
rpcBinding,
(LPWSTR) interfaceId,
OnlineAddressEnum,
PingAddressEnum
);
NmEndRpc(node->NodeId);
if(status != RPC_S_OK) {
NmDumpRpcExtErrorInfo(status);
}
NmpAcquireLock();
OmDereferenceObject(node);
}
if (status == ERROR_SUCCESS) {
if ((*PingAddressEnum)->AddressSize != sizeof(ULONG)) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Ping enum address size is invalid for interface %1!ws!\n",
interfaceId
);
status = ERROR_INCORRECT_ADDRESS;
midl_user_free(*PingAddressEnum);
*PingAddressEnum = NULL;
}
else {
ClRtlLogPrint(LOG_NOISE,
"[NM] Ping enum for interface %1!ws! contains %2!u! addresses\n",
interfaceId,
(*PingAddressEnum)->AddressCount
);
}
}
else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to get ping address enum for interface %1!ws!, status %2!u!\n",
interfaceId,
status
);
}
return(status);
} // NmpGetInterfacePingAddressEnum
DWORD
NmpDoInterfacePing(
IN PNM_INTERFACE Interface,
IN PNM_ADDRESS_ENUM PingAddressEnum,
OUT BOOLEAN * PingSucceeded
)
/*++
Notes:
Called with Interface referenced.
--*/
{
DWORD status = ERROR_SUCCESS;
LPCWSTR interfaceId = OmObjectId(Interface);
LPWSTR addressString;
DWORD maxAddressStringLength;
DWORD i;
ClRtlLogPrint(LOG_NOISE,
"[NM] Pinging targets for interface %1!ws!.\n",
interfaceId
);
*PingSucceeded = FALSE;
if (PingAddressEnum->AddressSize != sizeof(ULONG)) {
return(ERROR_INCORRECT_ADDRESS);
}
ClRtlQueryTcpipInformation(
&maxAddressStringLength,
NULL,
NULL
);
addressString = LocalAlloc(
LMEM_FIXED,
(maxAddressStringLength + 1) * sizeof(WCHAR)
);
if (addressString == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for address string.\n"
);
return(ERROR_NOT_ENOUGH_MEMORY);
}
for (i=0; i<PingAddressEnum->AddressCount; i++) {
status = ClRtlTcpipAddressToString(
(ULONG) PingAddressEnum->AddressList[i],
&addressString
);
if (status == ERROR_SUCCESS) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Pinging host %1!ws!\n",
addressString
);
}
else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert address %1!x! to string %2!u!.\n",
(ULONG) PingAddressEnum->AddressList[i],
status
);
}
if ( ClRtlIsDuplicateTcpipAddress(
(ULONG) PingAddressEnum->AddressList[i])
)
{
ClRtlLogPrint(LOG_NOISE,
"[NM] Ping of host %1!ws! succeeded.\n",
addressString
);
*PingSucceeded = TRUE;
break;
}
else {
ClRtlLogPrint(LOG_NOISE,
"[NM] Ping of host %1!ws! failed.\n",
addressString
);
}
}
LocalFree(addressString);
return(status);
} // NmpDoInterfacePing
DWORD
NmpTestInterfaceConnectivity(
PNM_INTERFACE Interface1,
PBOOLEAN Interface1HasConnectivity,
PNM_INTERFACE Interface2,
PBOOLEAN Interface2HasConnectivity
)
/*++
Notes:
Called with NmpLock held. This routine releases and reacquires the
NmpLock. It must be called with references on the target interfaces.
--*/
{
DWORD status, status1, status2;
PNM_NETWORK network = Interface1->Network;
PNM_INTERFACE localInterface = network->LocalInterface;
LPCWSTR networkId = OmObjectId(network);
LPCWSTR interface1Id = OmObjectId(Interface1);
LPCWSTR interface2Id = OmObjectId(Interface2);
ULONG interface1Address, interface2Address;
PNM_ADDRESS_ENUM pingEnum1 = NULL, pingEnum2 = NULL;
PNM_ADDRESS_ENUM onlineEnum1 = NULL, onlineEnum2 = NULL;
PNM_ADDRESS_ENUM unionPingEnum = NULL, unionOnlineEnum = NULL;
DWORD addressCount;
RPC_ASYNC_STATE async1, async2;
HANDLE event1 = NULL, event2 = NULL;
RPC_BINDING_HANDLE rpcBinding1 = NULL, rpcBinding2 = NULL;
DWORD i1, i2;
BOOL duplicate;
//
// Reference the nodes associated with the target interfaces so they
// can't go away during this process.
//
OmReferenceObject(Interface1->Node);
OmReferenceObject(Interface2->Node);
if (localInterface != NULL) {
OmReferenceObject(localInterface);
}
*Interface1HasConnectivity = *Interface2HasConnectivity = FALSE;
//
// Convert the interface address strings to binary form.
//
status = ClRtlTcpipStringToAddress(
Interface1->Address,
&interface1Address
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert interface address string %1!ws! to binary, status %2!u!.\n",
Interface1->Address,
status
);
goto error_exit;
}
status = ClRtlTcpipStringToAddress(
Interface2->Address,
&interface2Address
);
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to convert interface address string %1!ws! to binary, status %2!u!.\n",
Interface2->Address,
status
);
goto error_exit;
}
//
// Fetch the online address list from each of the interfaces.
// The NmpLock will be released when querying a remote interface.
//
status = NmpGetInterfaceOnlineAddressEnum(
Interface1,
&onlineEnum1
);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
status = NmpGetInterfaceOnlineAddressEnum(
Interface2,
&onlineEnum2
);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
//
// Bail out if either of the interfaces was deleted while the NmpLock
// was released.
//
if ((NM_DELETE_PENDING(Interface1) || NM_DELETE_PENDING(Interface2))) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Aborting interface connectivity test on network %1!ws! "
"because an interface was deleted.\n",
networkId
);
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
goto error_exit;
}
//
// Take the union of the two online lists
//
addressCount = onlineEnum1->AddressCount + onlineEnum2->AddressCount;
ClRtlLogPrint(LOG_NOISE,
"[NM] Total online address count for network %1!ws! is %2!u!\n",
networkId,
addressCount
);
if (addressCount == 0) {
unionOnlineEnum = LocalAlloc(LMEM_FIXED, sizeof(NM_ADDRESS_ENUM));
}
else {
unionOnlineEnum = LocalAlloc(
LMEM_FIXED,
sizeof(NM_ADDRESS_ENUM) +
((addressCount - 1) * sizeof(ULONGLONG))
);
}
if (unionOnlineEnum == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for union ping list.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_exit;
}
unionOnlineEnum->AddressSize = sizeof(ULONG);
unionOnlineEnum->AddressCount = 0;
if (onlineEnum1->AddressCount != 0) {
CopyMemory(
&(unionOnlineEnum->AddressList[0]),
&(onlineEnum1->AddressList[0]),
onlineEnum1->AddressCount * sizeof(ULONGLONG)
);
unionOnlineEnum->AddressCount = onlineEnum1->AddressCount;
}
if (onlineEnum2->AddressCount != 0) {
CopyMemory(
&(unionOnlineEnum->AddressList[unionOnlineEnum->AddressCount]),
&(onlineEnum2->AddressList[0]),
onlineEnum2->AddressCount * sizeof(ULONGLONG)
);
unionOnlineEnum->AddressCount += onlineEnum2->AddressCount;
}
midl_user_free(onlineEnum1); onlineEnum1 = NULL;
midl_user_free(onlineEnum2); onlineEnum2 = NULL;
//
// Fetch the ping target list from each of the interfaces.
// The NmpLock will be released when querying a remote interface.
//
status = NmpGetInterfacePingAddressEnum(
Interface1,
unionOnlineEnum,
&pingEnum1
);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
status = NmpGetInterfacePingAddressEnum(
Interface2,
unionOnlineEnum,
&pingEnum2
);
if (status != ERROR_SUCCESS) {
goto error_exit;
}
//
// Bail out if either of the interfaces was deleted while the NmpLock
// was released.
//
if ((NM_DELETE_PENDING(Interface1) || NM_DELETE_PENDING(Interface2))) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Aborting interface connectivity test on network %1!ws! "
"because an interface was deleted.\n",
networkId
);
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
goto error_exit;
}
NmpReleaseLock();
//
// Take the union of the two ping lists
//
addressCount = pingEnum1->AddressCount + pingEnum2->AddressCount;
ClRtlLogPrint(LOG_NOISE,
"[NM] Total ping address count for network %1!ws! is %2!u!\n",
networkId,
addressCount
);
if (addressCount == 0) {
status = ERROR_SUCCESS;
goto error_lock_and_exit;
}
unionPingEnum = LocalAlloc(
LMEM_FIXED,
sizeof(NM_ADDRESS_ENUM) +
( (NM_MAX_UNION_PING_ENUM_SIZE - 1) *
sizeof(ULONGLONG)
)
);
if (unionPingEnum == NULL) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate memory for union ping list.\n"
);
status = ERROR_NOT_ENOUGH_MEMORY;
goto error_lock_and_exit;
}
unionPingEnum->AddressSize = sizeof(ULONG);
unionPingEnum->AddressCount = 0;
i1 = 0; i2 = 0;
while (TRUE) {
while (i1 < pingEnum1->AddressCount) {
duplicate = NmpIsAddressInAddressEnum(
pingEnum1->AddressList[i1],
unionPingEnum
);
if (!duplicate) {
unionPingEnum->AddressList[unionPingEnum->AddressCount++] =
pingEnum1->AddressList[i1++];
break;
}
else {
i1++;
}
}
if (unionPingEnum->AddressCount == NM_MAX_UNION_PING_ENUM_SIZE) {
break;
}
while (i2 < pingEnum2->AddressCount) {
duplicate = NmpIsAddressInAddressEnum(
pingEnum2->AddressList[i2],
unionPingEnum
);
if (!duplicate) {
unionPingEnum->AddressList[unionPingEnum->AddressCount++] =
pingEnum2->AddressList[i2++];
break;
}
else {
i2++;
}
}
if ( (unionPingEnum->AddressCount == NM_MAX_UNION_PING_ENUM_SIZE) ||
( (i1 == pingEnum1->AddressCount) &&
(i2 == pingEnum2->AddressCount)
)
)
{
break;
}
}
midl_user_free(pingEnum1); pingEnum1 = NULL;
midl_user_free(pingEnum2); pingEnum2 = NULL;
ClRtlLogPrint(LOG_NOISE,
"[NM] Union ping list for network %1!ws! contains %2!u! addresses\n",
networkId,
unionPingEnum->AddressCount
);
//
// Ask each interface to ping the list of targets using async RPC calls
//
//
// Allocate resources for the async RPC calls
//
if (Interface1 != localInterface) {
event1 = CreateEvent(NULL, FALSE, FALSE, NULL);
if (event1 == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate event for async rpc, status %1!u!.\n",
status
);
goto error_lock_and_exit;
}
status = RpcAsyncInitializeHandle(&async1, sizeof(async1));
if (status != RPC_S_OK) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to initialize RPC async state, status %1!u!.\n",
status
);
goto error_lock_and_exit;
}
async1.NotificationType = RpcNotificationTypeEvent;
async1.u.hEvent = event1;
rpcBinding1 = Interface1->Node->IsolateRpcBinding;
}
if (Interface2 != localInterface) {
event2 = CreateEvent(NULL, FALSE, FALSE, NULL);
if (event2 == NULL) {
status = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to allocate event for async rpc, status %1!u!.\n",
status
);
goto error_lock_and_exit;
}
status = RpcAsyncInitializeHandle(&async2, sizeof(async2));
if (status != RPC_S_OK) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to initialize RPC async state, status %1!u!.\n",
status
);
goto error_lock_and_exit;
}
async2.NotificationType = RpcNotificationTypeEvent;
async2.u.hEvent = event2;
rpcBinding2 = Interface2->Node->IsolateRpcBinding;
}
if (rpcBinding1 != NULL) {
//
// Issue the RPC for interface1 first. Then deal with interface2
//
//
// We need the try-except until a bug is fixed in MIDL
//
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing RpcDoInterfacePing for interface %1!ws!\n",
interface1Id
);
status = ERROR_SUCCESS;
try {
NmRpcDoInterfacePing(
&async1,
rpcBinding1,
(LPWSTR) interface1Id,
unionPingEnum,
Interface1HasConnectivity,
&status1
);
} except(I_RpcExceptionFilter(RpcExceptionCode())) {
status = GetExceptionCode();
}
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] DoPing RPC failed for interface %1!ws!, status %2!u!.\n",
interface1Id,
status
);
goto error_lock_and_exit;
}
if (rpcBinding2 != NULL) {
//
// Issue the RPC for interface2.
//
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing RpcDoInterfacePing for interface %1!ws!\n",
interface2Id
);
status = ERROR_SUCCESS;
try {
NmRpcDoInterfacePing(
&async2,
rpcBinding2,
(LPWSTR) interface2Id,
unionPingEnum,
Interface2HasConnectivity,
&status2
);
} except(I_RpcExceptionFilter(RpcExceptionCode())) {
status = GetExceptionCode();
}
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] DoPing RPC failed for interface %1!ws!, status %2!u!.\n",
interface1Id,
status
);
goto error_lock_and_exit;
}
//
// Wait for the RPC for interface2 to complete
//
ClRtlLogPrint(LOG_NOISE,
"[NM] Waiting for RpcDoInterfacePing for interface %1!ws! to complete\n",
interface2Id
);
status = WaitForSingleObjectEx(event2, INFINITE, FALSE);
CL_ASSERT(status == WAIT_OBJECT_0);
status = RpcAsyncCompleteCall(
&async2,
&status2
);
CL_ASSERT(status == RPC_S_OK);
ClRtlLogPrint(LOG_NOISE,
"[NM] Wait for RpcDoInterfacePing for interface %1!ws! completed.\n",
interface2Id
);
}
else {
//
// Call the local routine for interface2.
//
status2 = NmpDoInterfacePing(
Interface2,
unionPingEnum,
Interface2HasConnectivity
);
}
//
// Wait for the RPC for interface1 to complete
//
ClRtlLogPrint(LOG_NOISE,
"[NM] Waiting for RpcDoInterfacePing for interface %1!ws! to complete\n",
interface1Id
);
status = WaitForSingleObjectEx(event1, INFINITE, FALSE);
CL_ASSERT(status == WAIT_OBJECT_0);
status = RpcAsyncCompleteCall(
&async1,
&status1
);
CL_ASSERT(status == RPC_S_OK);
ClRtlLogPrint(LOG_NOISE,
"[NM] Wait for RpcDoInterfacePing for interface %1!ws! completed.\n",
interface1Id
);
}
else {
//
// Send the RPC to interface2 first. Then call the local
// routine for interface1
//
CL_ASSERT(rpcBinding2 != NULL);
ClRtlLogPrint(LOG_NOISE,
"[NM] Issuing RpcDoInterfacePing for interface %1!ws!\n",
interface2Id
);
status = ERROR_SUCCESS;
try {
NmRpcDoInterfacePing(
&async2,
rpcBinding2,
(LPWSTR) interface2Id,
unionPingEnum,
Interface2HasConnectivity,
&status2
);
} except(I_RpcExceptionFilter(RpcExceptionCode())) {
status = GetExceptionCode();
}
if (status != ERROR_SUCCESS) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] DoPing RPC failed for interface %1!ws!, status %2!u!.\n",
interface1Id,
status
);
goto error_lock_and_exit;
}
status1 = NmpDoInterfacePing(
Interface1,
unionPingEnum,
Interface1HasConnectivity
);
//
// Wait for the RPC for interface2 to complete
//
ClRtlLogPrint(LOG_NOISE,
"[NM] Waiting for RpcDoInterfacePing for interface %1!ws! to complete\n",
interface2Id
);
status = WaitForSingleObject(event2, INFINITE);
CL_ASSERT(status == WAIT_OBJECT_0);
status = RpcAsyncCompleteCall(
&async2,
&status2
);
CL_ASSERT(status == RPC_S_OK);
ClRtlLogPrint(LOG_NOISE,
"[NM] Wait for RpcDoInterfacePing for interface %1!ws! completed.\n",
interface2Id
);
}
if (status1 != RPC_S_OK) {
status = status1;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] DoPing RPC failed for interface %1!ws!, status %2!u!.\n",
interface1Id,
status
);
goto error_lock_and_exit;
}
if (status2 != RPC_S_OK) {
status = status2;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] DoPing RPC failed for interface %1!ws!, status %2!u!.\n",
interface2Id,
status
);
goto error_lock_and_exit;
}
error_lock_and_exit:
NmpAcquireLock();
if ( (status == ERROR_SUCCESS) &&
(NM_DELETE_PENDING(Interface1) || NM_DELETE_PENDING(Interface2))
)
{
ClRtlLogPrint(LOG_NOISE,
"[NM] Aborting interface connectivity test on network %1!ws! "
"because an interface was deleted.\n",
networkId
);
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
}
error_exit:
OmDereferenceObject(Interface1->Node);
OmDereferenceObject(Interface2->Node);
if (localInterface != NULL) {
OmDereferenceObject(localInterface);
}
if (onlineEnum1 != NULL) {
midl_user_free(onlineEnum1);
}
if (onlineEnum2 != NULL) {
midl_user_free(onlineEnum2);
}
if (unionOnlineEnum != NULL) {
LocalFree(unionOnlineEnum);
}
if (pingEnum1 != NULL) {
midl_user_free(pingEnum1);
}
if (pingEnum2 != NULL) {
midl_user_free(pingEnum2);
}
if (unionPingEnum != NULL) {
LocalFree(unionPingEnum);
}
if (event1 != NULL) {
CloseHandle(event1);
}
if (event2 != NULL) {
CloseHandle(event2);
}
return(status);
} // NmpTestInterfaceConnectivity
/////////////////////////////////////////////////////////////////////////////
//
// Miscellaneous routines
//
/////////////////////////////////////////////////////////////////////////////
DWORD
NmpRegisterInterface(
IN PNM_INTERFACE Interface,
IN BOOLEAN RetryOnFailure
)
/*++
Called with the NmpLock held.
--*/
{
DWORD status;
LPWSTR interfaceId = (LPWSTR) OmObjectId(Interface);
PNM_NETWORK network = Interface->Network;
PVOID tdiAddress = NULL;
ULONG tdiAddressLength = 0;
NDIS_MEDIA_STATE mediaStatus;
CL_ASSERT(!NmpIsInterfaceRegistered(Interface));
ClRtlLogPrint(LOG_NOISE,
"[NM] Registering interface %1!ws! (%2!ws!) with cluster transport, "
"addr %3!ws!, endpoint %4!ws!.\n",
interfaceId,
OmObjectName(Interface),
Interface->Address,
Interface->ClusnetEndpoint
);
status = ClRtlBuildTcpipTdiAddress(
Interface->Address,
Interface->ClusnetEndpoint,
&tdiAddress,
&tdiAddressLength
);
if (status == ERROR_SUCCESS) {
status = ClusnetRegisterInterface(
NmClusnetHandle,
Interface->Node->NodeId,
Interface->Network->ShortId,
0,
Interface->AdapterId,
wcslen(Interface->AdapterId) * sizeof(WCHAR),
tdiAddress,
tdiAddressLength,
(PULONG) &mediaStatus
);
LocalFree(tdiAddress);
if (status == ERROR_SUCCESS) {
Interface->Flags |= NM_FLAG_IF_REGISTERED;
network->RegistrationRetryTimeout = 0;
//
// If this is a local interface, and if its media status
// indicates that it is connected, schedule a worker thread to
// deliver an interface up notification. Clusnet does not
// deliver interface up events for local interfaces.
//
if (network->LocalInterface == Interface) {
if (mediaStatus == NdisMediaStateConnected) {
network->Flags |= NM_FLAG_NET_REPORT_LOCAL_IF_UP;
NmpScheduleNetworkConnectivityReport(network);
} else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Local interface %1!ws! reported "
"disconnected.\n",
interfaceId,
status
);
network->Flags |= NM_FLAG_NET_REPORT_LOCAL_IF_FAILED;
NmpScheduleNetworkConnectivityReport(network);
}
}
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to register interface %1!ws! with cluster "
"transport, status %2!u!.\n",
interfaceId,
status
);
}
}
else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Failed to build TDI bind address for interface %1!ws!, "
"status %2!u!.\n",
interfaceId,
status
);
}
if (status != ERROR_SUCCESS) {
WCHAR string[16];
wsprintfW(&(string[0]), L"%u", status);
CsLogEvent3(
LOG_UNUSUAL,
NM_EVENT_REGISTER_NETINTERFACE_FAILED,
OmObjectName(Interface->Node),
OmObjectName(Interface->Network),
string
);
//
// Retry if the error is transient
//
if ( RetryOnFailure &&
( (status == ERROR_INVALID_NETNAME) ||
(status == ERROR_NOT_ENOUGH_MEMORY) ||
(status == ERROR_NO_SYSTEM_RESOURCES)
)
)
{
NmpStartNetworkRegistrationRetryTimer(network);
status = ERROR_SUCCESS;
}
}
return(status);
} // NmpRegisterInterface
VOID
NmpDeregisterInterface(
IN PNM_INTERFACE Interface
)
/*++
Routine Description:
Deregisters an interface from the cluster transport.
Arguments:
Interface - A pointer to the interface to deregister.
Return Value:
None.
Notes:
Called with the NmpLock held.
--*/
{
DWORD status;
CL_ASSERT(NmpIsInterfaceRegistered(Interface));
ClRtlLogPrint(LOG_NOISE,
"[NM] Deregistering interface %1!ws! (%2!ws!) from cluster "
"transport.\n",
OmObjectId(Interface),
OmObjectName(Interface)
);
status = ClusnetDeregisterInterface(
NmClusnetHandle,
Interface->Node->NodeId,
Interface->Network->ShortId
);
CL_ASSERT(
(status == ERROR_SUCCESS) ||
(status == ERROR_CLUSTER_NETINTERFACE_NOT_FOUND)
);
Interface->Flags &= ~NM_FLAG_IF_REGISTERED;
return;
} // NmpDeregisterNetwork
DWORD
NmpPrepareToCreateInterface(
IN PNM_INTERFACE_INFO2 InterfaceInfo,
OUT PNM_NETWORK * Network,
OUT PNM_NODE * Node
)
{
DWORD status;
PNM_INTERFACE netInterface = NULL;
PNM_NODE node = NULL;
PNM_NETWORK network = NULL;
PLIST_ENTRY entry;
*Node = NULL;
*Network = NULL;
//
// Verify that the associated node and network objects exist.
//
network = OmReferenceObjectById(
ObjectTypeNetwork,
InterfaceInfo->NetworkId
);
if (network == NULL) {
status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Network %1!ws! does not exist. Cannot create "
"interface %2!ws!\n",
InterfaceInfo->NetworkId,
InterfaceInfo->Id
);
goto error_exit;
}
node = OmReferenceObjectById(ObjectTypeNode, InterfaceInfo->NodeId);
if (node == NULL) {
status = ERROR_CLUSTER_NODE_NOT_FOUND;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Node %1!ws! does not exist. Cannot create interface %2!ws!\n",
InterfaceInfo->NodeId,
InterfaceInfo->Id
);
goto error_exit;
}
//
// Verify that the interface doesn't already exist.
//
NmpAcquireLock();
for ( entry = node->InterfaceList.Flink;
entry != &(node->InterfaceList);
entry = entry->Flink
)
{
netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NodeLinkage);
if (netInterface->Network == network) {
status = ERROR_CLUSTER_NETINTERFACE_EXISTS;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] An interface already exists for node %1!ws! on network %2!ws!\n",
InterfaceInfo->NodeId,
InterfaceInfo->NetworkId
);
NmpReleaseLock();
goto error_exit;
}
}
NmpReleaseLock();
//
// Verify that the specified interface ID is unique.
//
netInterface = OmReferenceObjectById(
ObjectTypeNetInterface,
InterfaceInfo->Id
);
if (netInterface != NULL) {
OmDereferenceObject(netInterface);
status = ERROR_CLUSTER_NETINTERFACE_EXISTS;
ClRtlLogPrint(LOG_CRITICAL,
"[NM] An interface with ID %1!ws! already exists\n",
InterfaceInfo->Id
);
goto error_exit;
}
*Node = node;
*Network = network;
return(ERROR_SUCCESS);
error_exit:
if (network != NULL) {
OmDereferenceObject(network);
}
if (node != NULL) {
OmDereferenceObject(node);
}
return(status);
} // NmpPrepareToCreateInterface
PNM_INTERFACE
NmpGetInterfaceForNodeAndNetworkById(
IN CL_NODE_ID NodeId,
IN CL_NETWORK_ID NetworkId
)
/*++
Routine Description:
Give the node Id and network short Id, return a pointer to
the intersecting interface object
Arguments:
NodeId - The ID of the node associated with this interface
NetworkId - The short Id of the network associated with this interface
Return Value:
A pointer to the interface object if successful.
NULL if unsuccessful. Extended error information is available from
GetLastError().
Notes:
Called with the NmpLock held.
--*/
{
DWORD status;
PNM_NODE node = NmpIdArray[NodeId];
if (node != NULL) {
PLIST_ENTRY entry;
PNM_INTERFACE netInterface;
//
// run down the list of interfaces associated with this node,
// looking for one whose network matches the specified short ID
//
for (entry = node->InterfaceList.Flink;
entry != &(node->InterfaceList);
entry = entry->Flink
)
{
netInterface = CONTAINING_RECORD(
entry,
NM_INTERFACE,
NodeLinkage
);
if (netInterface->Network->ShortId == NetworkId) {
return(netInterface);
}
}
status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
}
else {
status = ERROR_CLUSTER_NODE_NOT_FOUND;
}
SetLastError(status);
return(NULL);
} // NmpGetInterfaceForNodeAndNetworkById
DWORD
NmpConvertPropertyListToInterfaceInfo(
IN PVOID InterfacePropertyList,
IN DWORD InterfacePropertyListSize,
PNM_INTERFACE_INFO2 InterfaceInfo
)
{
DWORD status;
//
// Unmarshall the property list.
//
ZeroMemory(InterfaceInfo, sizeof(NM_INTERFACE_INFO2));
status = ClRtlVerifyPropertyTable(
NmpInterfaceProperties,
NULL, // Reserved
FALSE, // Don't allow unknowns
InterfacePropertyList,
InterfacePropertyListSize,
(LPBYTE) InterfaceInfo
);
if (status == ERROR_SUCCESS) {
InterfaceInfo->NetIndex = NmInvalidInterfaceNetIndex;
}
return(status);
} // NmpConvertPropertyListToInterfaceInfo
BOOLEAN
NmpVerifyLocalInterfaceConnected(
IN PNM_INTERFACE Interface
)
/*++
Routine Description:
Queries local interface adapter for current media
status using an NDIS ioctl.
Arguments:
Interface - interface object for local adapter to query
Return value:
TRUE if media status is connected or cannot be determined
FALSE if media status is disconnected
Notes:
Called and returns with NM lock acquired.
--*/
{
PWCHAR adapterDevNameBuffer = NULL;
PWCHAR adapterDevNamep, prefix, brace;
DWORD prefixSize, allocSize, adapterIdSize;
DWORD status = ERROR_SUCCESS;
UNICODE_STRING adapterDevName;
NIC_STATISTICS ndisStats;
BOOLEAN mediaConnected = TRUE;
// verify parameters
if (Interface == NULL || Interface->AdapterId == NULL) {
return TRUE;
}
// the adapter device name is of the form
//
// \Device\{AdapterIdGUID}
//
// the AdapterId field in the NM_INTERFACE structure is
// currently not enclosed in braces, but we handle the
// case where it is.
// set up the adapter device name prefix
prefix = L"\\Device\\";
prefixSize = wcslen(prefix) * sizeof(WCHAR);
// allocate a buffer for the adapter device name.
adapterIdSize = wcslen(Interface->AdapterId) * sizeof(WCHAR);
allocSize = prefixSize + adapterIdSize + sizeof(UNICODE_NULL);
brace = L"{";
if (*((PWCHAR)Interface->AdapterId) != *brace) {
allocSize += 2 * sizeof(WCHAR);
}
adapterDevNameBuffer = LocalAlloc(LMEM_FIXED, allocSize);
if (adapterDevNameBuffer == NULL) {
ClRtlLogPrint(
LOG_UNUSUAL,
"[NM] Failed to allocate device name buffer for "
"adapter %1!ws!. Assuming adapter is connected.\n",
Interface->AdapterId
);
return(TRUE);
}
// build the adapter device name from the adapter ID
ZeroMemory(adapterDevNameBuffer, allocSize);
adapterDevNamep = adapterDevNameBuffer;
CopyMemory(adapterDevNamep, prefix, prefixSize);
adapterDevNamep += prefixSize / sizeof(WCHAR);
if (*((PWCHAR)Interface->AdapterId) != *brace) {
*adapterDevNamep = *brace;
adapterDevNamep++;
}
CopyMemory(adapterDevNamep, Interface->AdapterId, adapterIdSize);
if (*((PWCHAR)Interface->AdapterId) != *brace) {
brace = L"}";
adapterDevNamep += adapterIdSize / sizeof(WCHAR);
*adapterDevNamep = *brace;
}
RtlInitUnicodeString(&adapterDevName, (LPWSTR)adapterDevNameBuffer);
// query the adapter for NDIS statistics
ZeroMemory(&ndisStats, sizeof(ndisStats));
ndisStats.Size = sizeof(ndisStats);
if (!NdisQueryStatistics(&adapterDevName, &ndisStats)) {
status = GetLastError();
ClRtlLogPrint(
LOG_UNUSUAL,
"[NM] NDIS statistics query to adapter %1!ws! failed, "
"error %2!u!. Assuming adapter is connected.\n",
Interface->AdapterId, status
);
} else {
if (ndisStats.MediaState == MEDIA_STATE_DISCONNECTED) {
mediaConnected = FALSE;
}
}
LocalFree(adapterDevNameBuffer);
return(mediaConnected);
} // NmpVerifyLocalInterfaceConnected