mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7463 lines
198 KiB
7463 lines
198 KiB
/*++
|
|
|
|
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
|
|
|
|
|