7464 lines
198 KiB
C
7464 lines
198 KiB
C
/*++
|
||
|
||
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
|
||
|
||
|