789 lines
28 KiB
C++
789 lines
28 KiB
C++
|
/*
|
||
|
* File: notification.cpp
|
||
|
* Description: Support for connection notification.
|
||
|
* Author: shouse 4.30.01
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include <iphlpapi.h>
|
||
|
#include "debug.h"
|
||
|
#include "notification.tmh"
|
||
|
|
||
|
extern DWORD MapStateFromDriverToApi(DWORD dwDriverState);
|
||
|
|
||
|
/* The length of the IP to GUID hash table. */
|
||
|
#define IP_TO_GUID_HASH 19
|
||
|
|
||
|
/* Loopback IP address. (127.0.0.1) */
|
||
|
#define IP_LOOPBACK_ADDRESS 0x0100007f
|
||
|
|
||
|
/* Spin count mask specifying a preallocated event for use by InitializeCriticalSectionAndSpinCount */
|
||
|
#define PREALLOC_CRITSECT_SPIN_COUNT 0x80000000
|
||
|
|
||
|
/* An Ip to GUID table entry. */
|
||
|
typedef struct IPToGUIDEntry {
|
||
|
ULONG dwIPAddress;
|
||
|
WCHAR szAdapterGUID[CVY_MAX_DEVNAME_LEN];
|
||
|
IPToGUIDEntry * pNext;
|
||
|
} IPToGUIDEntry;
|
||
|
|
||
|
/* The WLBS device - necessary for IOCTLs. */
|
||
|
WCHAR szDevice[CVY_STR_SIZE];
|
||
|
|
||
|
/* The IP to GUID map is an array of linked lists hashed on IP address. */
|
||
|
IPToGUIDEntry * IPToGUIDMap[IP_TO_GUID_HASH];
|
||
|
|
||
|
/* An overlapped structure for IP address change notifications. */
|
||
|
OVERLAPPED AddrChangeOverlapped;
|
||
|
|
||
|
/* A handle for IP address change notifications. */
|
||
|
HANDLE hAddrChangeHandle;
|
||
|
|
||
|
/* A handle for an IP address change event. */
|
||
|
HANDLE hAddrChangeEvent;
|
||
|
|
||
|
/* A preallocated critical section for IP address change notifications to
|
||
|
protect against one thread of execution tearing down notification state
|
||
|
while another is using it. */
|
||
|
CRITICAL_SECTION csConnectionNotify;
|
||
|
|
||
|
/* A boolean to indicate whether or not connection notification has been initialized.
|
||
|
Initialization is performed upon the first call to either WlbsConnectionUp or WlbsConnectionDown. */
|
||
|
static BOOL fInitialized = FALSE;
|
||
|
|
||
|
/*
|
||
|
* Function: GetGUIDFromIP
|
||
|
* Description: Gets the GUID from the IPToGUID table corresponding to the
|
||
|
* the given IP address.
|
||
|
* Returns: If the call succeeds, returns a pointer to the unicode string
|
||
|
* containing the CLSID (GUID). Upon failure, returns NULL.
|
||
|
* Author: shouse 6.15.00
|
||
|
*/
|
||
|
WCHAR * GetGUIDFromIP (ULONG IPAddress) {
|
||
|
TRACE_VERB("->%!FUNC!");
|
||
|
|
||
|
IPToGUIDEntry * entry = NULL;
|
||
|
|
||
|
/* Loop through the linked list at the hashed index and return the GUID from the entry
|
||
|
corresponding to the given IP address. */
|
||
|
for (entry = IPToGUIDMap[IPAddress % IP_TO_GUID_HASH]; entry; entry = entry->pNext)
|
||
|
{
|
||
|
if (entry->dwIPAddress == IPAddress)
|
||
|
{
|
||
|
if (NULL != entry->szAdapterGUID) TRACE_VERB("->%!FUNC! return guid %ls", entry->szAdapterGUID);
|
||
|
else TRACE_VERB("->%!FUNC! return guid which is NULL");
|
||
|
return entry->szAdapterGUID;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* At this point, we can't find the IP address in the table, so bail. */
|
||
|
TRACE_VERB("<-%!FUNC! return NULL");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: GetGUIDFromIndex
|
||
|
* Description: Gets the GUID from the AdaptersInfo table corresponding
|
||
|
* to the given IP address.
|
||
|
* Returns: If the call succeeds, returns a pointer to the string containing
|
||
|
* the adapter name (GUID). Upon failure, returns NULL.
|
||
|
* Author: shouse 6.15.00
|
||
|
*/
|
||
|
CHAR * GetGUIDFromIndex (PIP_ADAPTER_INFO pAdapterTable, DWORD dwIndex) {
|
||
|
TRACE_VERB("->%!FUNC!");
|
||
|
|
||
|
PIP_ADAPTER_INFO pAdapterInfo = NULL;
|
||
|
|
||
|
/* Loop through the adapter table looking for the given index. Return the adapter
|
||
|
name for the corresponding index. */
|
||
|
for (pAdapterInfo = pAdapterTable; pAdapterInfo; pAdapterInfo = pAdapterInfo->Next)
|
||
|
{
|
||
|
if (pAdapterInfo->Index == dwIndex)
|
||
|
{
|
||
|
TRACE_VERB("->%!FUNC! return guid %s", pAdapterInfo->AdapterName);
|
||
|
return pAdapterInfo->AdapterName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* If we get this far, we can't find it, so bail. */
|
||
|
TRACE_VERB("<-%!FUNC! return NULL");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: PrintIPAddress
|
||
|
* Description: Prints an IP address in dot notation.
|
||
|
* Returns:
|
||
|
* Author: shouse 6.15.00
|
||
|
*/
|
||
|
void PrintIPAddress (ULONG IPAddress) {
|
||
|
CHAR szIPAddress[16];
|
||
|
HRESULT hresult;
|
||
|
|
||
|
hresult = StringCbPrintfA(szIPAddress, sizeof(szIPAddress), "%d.%d.%d.%d",
|
||
|
IPAddress & 0x000000ff, (IPAddress & 0x0000ff00) >> 8,
|
||
|
(IPAddress & 0x00ff0000) >> 16, (IPAddress & 0xff000000) >> 24);
|
||
|
|
||
|
if (SUCCEEDED(hresult))
|
||
|
{
|
||
|
TRACE_VERB("%!FUNC! %-15s", szIPAddress);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: PrintIPToGUIDMap
|
||
|
* Description: Traverses and prints the IPToGUID map.
|
||
|
* Returns:
|
||
|
* Author: shouse 6.15.00
|
||
|
*/
|
||
|
void PrintIPToGUIDMap (void) {
|
||
|
IPToGUIDEntry * entry = NULL;
|
||
|
DWORD dwHash;
|
||
|
|
||
|
/* Loop through the linked list at each hashed index and print the IP to GUID mapping. */
|
||
|
for (dwHash = 0; dwHash < IP_TO_GUID_HASH; dwHash++) {
|
||
|
for (entry = IPToGUIDMap[dwHash]; entry; entry = entry->pNext) {
|
||
|
PrintIPAddress(entry->dwIPAddress);
|
||
|
TRACE_VERB("%!FUNC! -> GUID %ws\n", entry->szAdapterGUID);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: DestroyIPToGUIDMap
|
||
|
* Description: Destroys the IPToGUID map.
|
||
|
* Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
|
||
|
* Author: shouse 6.15.00
|
||
|
* Modified: chrisdar 07.23.02 - Changed to return void. If this function fails there isn't
|
||
|
* anything we can do about it. When bailing if HeapFree failed we didn't
|
||
|
* NULL the pointer, hence we had an invalid pointer.
|
||
|
*/
|
||
|
void DestroyIPToGUIDMap (void) {
|
||
|
TRACE_VERB("->%!FUNC!");
|
||
|
|
||
|
IPToGUIDEntry * next = NULL;
|
||
|
DWORD dwHash;
|
||
|
|
||
|
/* Loop through all hash indexes. */
|
||
|
for (dwHash = 0; dwHash < IP_TO_GUID_HASH; dwHash++) {
|
||
|
next = IPToGUIDMap[dwHash];
|
||
|
|
||
|
/* Loop through the linked list and free each entry. */
|
||
|
while (next) {
|
||
|
IPToGUIDEntry * entry = NULL;
|
||
|
|
||
|
entry = next;
|
||
|
next = next->pNext;
|
||
|
|
||
|
if (!HeapFree(GetProcessHeap(), 0, entry)) {
|
||
|
//
|
||
|
// Don't abort on error because we need to clean up the whole table.
|
||
|
//
|
||
|
TRACE_CRIT("%!FUNC! memory deallocation failed with %d", GetLastError());
|
||
|
}
|
||
|
|
||
|
entry = NULL;
|
||
|
}
|
||
|
|
||
|
/* Reset the pointer to the head of the list in the array. */
|
||
|
IPToGUIDMap[dwHash] = NULL;
|
||
|
}
|
||
|
|
||
|
TRACE_VERB("<-%!FUNC! return void");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: BuildIPToGUIDMap
|
||
|
* Description: Builds the IPToGUID map by first getting information on all adapters and
|
||
|
* then retrieving the map of IP addresses to adapters. Using those tables,
|
||
|
* this constructs a mapping of IP addresses to adapter GUIDs.
|
||
|
* Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
|
||
|
* Author: shouse 6.14.00
|
||
|
* Modified: chrisdar 07.24.02 Free dynamically allocated memory when an error occurs.
|
||
|
* Also no longer ignore failures in strsafe functions as this makes
|
||
|
* the table entries useless.
|
||
|
*/
|
||
|
//
|
||
|
// TODO: 24 July 2002 chrisdar
|
||
|
// Three issues need to be fixed in this function:
|
||
|
// 1. Method of allocating memory for output of GetAdaptersInfo can fail if adapter
|
||
|
// list changes between calls. This was seen in testing.
|
||
|
// 2. Same as 1. except for output of GetIpAddrTable.
|
||
|
// 3. Output from GetAdaptersInfo has all of the information needed (except that
|
||
|
// IPs are strings instead of dwords). Remove calls to GetIpAddrTable and modify
|
||
|
// logic to use output of GetAdaptersInfo.
|
||
|
//
|
||
|
DWORD BuildIPToGUIDMap (void) {
|
||
|
TRACE_VERB("->%!FUNC!");
|
||
|
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
PMIB_IPADDRTABLE pAddressTable = NULL;
|
||
|
PIP_ADAPTER_INFO pAdapterTable = NULL;
|
||
|
DWORD dwAddressSize = 0;
|
||
|
DWORD dwAdapterSize = 0;
|
||
|
DWORD dwEntry;
|
||
|
HRESULT hresult;
|
||
|
|
||
|
/* Destroy the IP to GUID map first. */
|
||
|
DestroyIPToGUIDMap();
|
||
|
|
||
|
/* Query the necessary length of a buffer to hold the adapter info. */
|
||
|
if ((dwError = GetAdaptersInfo(pAdapterTable, &dwAdapterSize)) != ERROR_BUFFER_OVERFLOW) {
|
||
|
TRACE_CRIT("%!FUNC! GetAdaptersInfo for buffer size failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Allocate a buffer of the indicated size. */
|
||
|
if (!(pAdapterTable = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, dwAdapterSize))) {
|
||
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE_CRIT("%!FUNC! memory allocation for adapter table failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Fill the buffer with the adapter info. */
|
||
|
if ((dwError = GetAdaptersInfo(pAdapterTable, &dwAdapterSize)) != NO_ERROR) {
|
||
|
TRACE_CRIT("%!FUNC! GetAdaptersInfo for filling adapter buffer failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Query the necessary length of a buffer to hold the IP address table. */
|
||
|
if ((dwError = GetIpAddrTable(pAddressTable, &dwAddressSize, TRUE)) != ERROR_INSUFFICIENT_BUFFER) {
|
||
|
TRACE_CRIT("%!FUNC! GetIpAddrTable for IP address length failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Allocate a buffer of the indicated size. */
|
||
|
if (!(pAddressTable = (PMIB_IPADDRTABLE)HeapAlloc(GetProcessHeap(), 0, dwAddressSize))) {
|
||
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE_CRIT("%!FUNC! memory allocation for IP address failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Fill the buffer with the IP address table. */
|
||
|
if ((dwError = GetIpAddrTable(pAddressTable, &dwAddressSize, TRUE)) != NO_ERROR) {
|
||
|
TRACE_CRIT("%!FUNC! GetIpAddrTable for filling IP address buffer failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* For each entry in the IP address to adapter table, create an entry for our IP address to GUID table. */
|
||
|
for (dwEntry = 0; dwEntry < pAddressTable->dwNumEntries; dwEntry++) {
|
||
|
PCHAR pszDeviceName = NULL;
|
||
|
IPToGUIDEntry * entry = NULL;
|
||
|
|
||
|
/* Only create an entry if the IP address is nonzero and is not the IP loopback address. */
|
||
|
if ((pAddressTable->table[dwEntry].dwAddr != 0UL) && (pAddressTable->table[dwEntry].dwAddr != IP_LOOPBACK_ADDRESS)) {
|
||
|
WCHAR szAdapterGUID[CVY_MAX_DEVNAME_LEN];
|
||
|
|
||
|
/* Retrieve the GUID from the interface index. */
|
||
|
if (!(pszDeviceName = GetGUIDFromIndex(pAdapterTable, pAddressTable->table[dwEntry].dwIndex))) {
|
||
|
dwError = ERROR_INCORRECT_ADDRESS;
|
||
|
TRACE_CRIT("%!FUNC! failed retriving interface index from guid with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Allocate a buffer for the IP to GUID entry. */
|
||
|
if (!(entry = (IPToGUIDEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(IPToGUIDEntry)))) {
|
||
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
TRACE_CRIT("%!FUNC! memory allocation failure for the IP to guid entry");
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Zero the entry contents. */
|
||
|
ZeroMemory((VOID *)entry, sizeof(entry));
|
||
|
|
||
|
/* Insert the entry at the head of the linked list indexed by the IP address % HASH. */
|
||
|
entry->pNext = IPToGUIDMap[pAddressTable->table[dwEntry].dwAddr % IP_TO_GUID_HASH];
|
||
|
IPToGUIDMap[pAddressTable->table[dwEntry].dwAddr % IP_TO_GUID_HASH] = entry;
|
||
|
|
||
|
/* Fill in the IP address. */
|
||
|
entry->dwIPAddress = pAddressTable->table[dwEntry].dwAddr;
|
||
|
|
||
|
/* GUIDS in NLB multi-NIC are expected to be prefixed with "\DEVICE\". */
|
||
|
hresult = StringCbCopy(entry->szAdapterGUID, sizeof(entry->szAdapterGUID), L"\\DEVICE\\");
|
||
|
if (FAILED(hresult))
|
||
|
{
|
||
|
dwError = (DWORD) hresult;
|
||
|
TRACE_CRIT("%!FUNC! string copy failed for DEVICE, Error code : 0x%x", HRESULT_CODE(hresult));
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Convert the adapter name ASCII string to a GUID unicode string and place it in the table entry. */
|
||
|
if (!MultiByteToWideChar(CP_ACP, 0, pszDeviceName, -1, szAdapterGUID, CVY_MAX_DEVNAME_LEN)) {
|
||
|
dwError = GetLastError();
|
||
|
TRACE_CRIT("%!FUNC! converting ascii string to guid failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Cat the GUID onto the "\DEVICE\". */
|
||
|
hresult = StringCbCat(entry->szAdapterGUID, sizeof(entry->szAdapterGUID), szAdapterGUID);
|
||
|
if (FAILED(hresult))
|
||
|
{
|
||
|
dwError = (DWORD) hresult;
|
||
|
TRACE_CRIT("%!FUNC! string append of guid failed, Error code : 0x%x", HRESULT_CODE(hresult));
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE_INFO("%!FUNC! IP address passed is either 0 or localhost. Skipping it.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Note that this printing is for debug purposes only. It is left enabled in all builds because it
|
||
|
// only calls TRACE_VERB for ouput.
|
||
|
//
|
||
|
PrintIPToGUIDMap();
|
||
|
|
||
|
exit:
|
||
|
|
||
|
/* Free the buffers used to query the IP stack. */
|
||
|
if (pAddressTable) HeapFree(GetProcessHeap(), 0, pAddressTable);
|
||
|
if (pAdapterTable) HeapFree(GetProcessHeap(), 0, pAdapterTable);
|
||
|
|
||
|
TRACE_VERB("<-%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: WlbsConnectionNotificationInit
|
||
|
* Description: Initialize connection notification by retrieving the device driver
|
||
|
* information for later use by IOCTLs and build the IPToGUID map.
|
||
|
* Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
|
||
|
* Author: shouse 6.15.00
|
||
|
*/
|
||
|
DWORD WlbsConnectionNotificationInit (void) {
|
||
|
TRACE_VERB("->%!FUNC!");
|
||
|
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
WCHAR szDriver[CVY_STR_SIZE];
|
||
|
HRESULT hresult;
|
||
|
|
||
|
hresult = StringCbPrintf(szDevice, sizeof(szDevice), L"\\\\.\\%ls", CVY_NAME);
|
||
|
if (FAILED(hresult))
|
||
|
{
|
||
|
dwError = HRESULT_CODE(hresult);
|
||
|
TRACE_CRIT("%!FUNC! StringCbPrintf failed, Error code : 0x%x", dwError);
|
||
|
TRACE_VERB("<-%!FUNC! return 0x%x", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Query for the existence of the WLBS driver. */
|
||
|
if (!QueryDosDevice(szDevice + 4, szDriver, CVY_STR_SIZE)) {
|
||
|
dwError = GetLastError();
|
||
|
TRACE_CRIT("%!FUNC! querying for nlb driver failed with %d", dwError);
|
||
|
TRACE_VERB("<-%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Build the IP to GUID mapping. */
|
||
|
if ((dwError = BuildIPToGUIDMap()) != ERROR_SUCCESS) {
|
||
|
TRACE_CRIT("%!FUNC! ip to guid map failed with %d", dwError);
|
||
|
TRACE_VERB("<-%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Create an IP address change event. */
|
||
|
if (!(hAddrChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) {
|
||
|
dwError = GetLastError();
|
||
|
TRACE_CRIT("%!FUNC! create event failed with %d", dwError);
|
||
|
TRACE_VERB("<-%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Clear the overlapped structure. */
|
||
|
ZeroMemory(&AddrChangeOverlapped, sizeof(OVERLAPPED));
|
||
|
|
||
|
/* Place the event handle in the overlapped structure. */
|
||
|
AddrChangeOverlapped.hEvent = hAddrChangeEvent;
|
||
|
|
||
|
/* Tell IP to notify us of any changes to the IP address to interface mapping. */
|
||
|
dwError = NotifyAddrChange(&hAddrChangeHandle, &AddrChangeOverlapped);
|
||
|
|
||
|
if ((dwError != NO_ERROR) && (dwError != ERROR_IO_PENDING)) {
|
||
|
TRACE_CRIT("%!FUNC! register of event with ip failed with %d", dwError);
|
||
|
TRACE_VERB("<-%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
TRACE_VERB("<-%!FUNC! return %d", ERROR_SUCCESS);
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: ResolveAddressTableChanges
|
||
|
* Description: Checks for changes in the IP address to adapter mapping and rebuilds the
|
||
|
* IPToGUID map if necessary.
|
||
|
* Returns: Returns ERROR_SUCCESS upon success. Returns an error code otherwise.
|
||
|
* Author: shouse 6.20.00
|
||
|
*/
|
||
|
DWORD ResolveAddressTableChanges (void) {
|
||
|
TRACE_VERB("->%!FUNC!");
|
||
|
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
DWORD dwLength = 0;
|
||
|
|
||
|
/* Check to see if the IP address to adapter table has been modified. */
|
||
|
if (GetOverlappedResult(hAddrChangeHandle, &AddrChangeOverlapped, &dwLength, FALSE)) {
|
||
|
TRACE_INFO("%!FUNC! IP address to adapter table modified... Rebuilding IP to GUID map...");
|
||
|
|
||
|
/* If so, rebuild the IP address to GUID mapping. */
|
||
|
if ((dwError = BuildIPToGUIDMap()) != ERROR_SUCCESS) {
|
||
|
TRACE_CRIT("%!FUNC! ip to guid map failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Tell IP to notify us of any changes to the IP address to interface mapping. */
|
||
|
dwError = NotifyAddrChange(&hAddrChangeHandle, &AddrChangeOverlapped);
|
||
|
|
||
|
if ((dwError == NO_ERROR) || (dwError == ERROR_IO_PENDING))
|
||
|
{
|
||
|
dwError = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE_CRIT("%!FUNC! register of event with ip failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
if (dwError == ERROR_IO_PENDING || dwError == ERROR_IO_INCOMPLETE)
|
||
|
{
|
||
|
dwError = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE_CRIT("%!FUNC! GetOverlappedResult failed with %d", dwError);
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: MapExtendedStatusToWin32
|
||
|
* Description: Converts the status code returned by the driver into a Win32 error code defined in winerror.h.
|
||
|
* Returns: A Win32 error code.
|
||
|
* Author: shouse, 9.7.01
|
||
|
* Notes:
|
||
|
*/
|
||
|
DWORD MapExtendedStatusToWin32 (DWORD dwDriverState) {
|
||
|
|
||
|
struct STATE_MAP {
|
||
|
DWORD dwDriverState;
|
||
|
DWORD dwApiState;
|
||
|
} StateMap[] = {
|
||
|
{IOCTL_CVY_BAD_PARAMS, ERROR_INVALID_PARAMETER},
|
||
|
{IOCTL_CVY_NOT_FOUND, ERROR_NOT_FOUND},
|
||
|
{IOCTL_CVY_GENERIC_FAILURE, ERROR_GEN_FAILURE},
|
||
|
{IOCTL_CVY_REQUEST_REFUSED, ERROR_REQUEST_REFUSED},
|
||
|
{IOCTL_CVY_OK, ERROR_SUCCESS}
|
||
|
};
|
||
|
|
||
|
for (int i = 0; i < sizeof(StateMap) / sizeof(StateMap[0]); i++) {
|
||
|
if (StateMap[i].dwDriverState == dwDriverState)
|
||
|
return StateMap[i].dwApiState;
|
||
|
}
|
||
|
|
||
|
/* If we can't find the appropriate driver error code in the map, return failure. */
|
||
|
return ERROR_GEN_FAILURE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: WlbsCancelConnectionNotify
|
||
|
* Description: Cancel IP route and address change notifications from TCP/IP. Call this once after any call to WlbsConnectionNotify.
|
||
|
* Returns: dwError - DWORD status = ERROR_SUCCESS if call is successful.
|
||
|
* Author: chrisdar 7.16.02
|
||
|
*/
|
||
|
DWORD WINAPI WlbsCancelConnectionNotify()
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
|
||
|
TRACE_VERB("-> %!FUNC!");
|
||
|
|
||
|
EnterCriticalSection(&csConnectionNotify);
|
||
|
|
||
|
if (!fInitialized)
|
||
|
{
|
||
|
TRACE_VERB("%!FUNC! notification cleanup is not needed...exiting.");
|
||
|
goto end;
|
||
|
}
|
||
|
|
||
|
if (CancelIPChangeNotify(&AddrChangeOverlapped))
|
||
|
{
|
||
|
DWORD BytesTrans;
|
||
|
//
|
||
|
// Block until the cancel operation completes
|
||
|
//
|
||
|
if (!GetOverlappedResult(&hAddrChangeHandle, &AddrChangeOverlapped, &BytesTrans, TRUE))
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
if (dwError == ERROR_OPERATION_ABORTED)
|
||
|
{
|
||
|
//
|
||
|
// This is the expected status since we canceled IP change notifications. Overwrite with success for caller.
|
||
|
//
|
||
|
dwError = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE_CRIT("%!FUNC! GetOverlappedResult failed with error 0x%x", dwError);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Failure conditions are:
|
||
|
// Requested operation already in progress
|
||
|
// There is no notification to cancel
|
||
|
// Neither is a critical error but tell the user about it since this shouldn't happen.
|
||
|
//
|
||
|
dwError = GetLastError();
|
||
|
TRACE_INFO("%!FUNC! CancelIPChangeNotify failed with error 0x%x", dwError);
|
||
|
}
|
||
|
|
||
|
if (!CloseHandle(hAddrChangeEvent))
|
||
|
{
|
||
|
//
|
||
|
// Don't return this status to caller. Just absorb it.
|
||
|
//
|
||
|
TRACE_CRIT("%!FUNC! CloseHandle failed with error 0x%x", GetLastError());
|
||
|
}
|
||
|
|
||
|
hAddrChangeEvent = INVALID_HANDLE_VALUE;
|
||
|
AddrChangeOverlapped.hEvent = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
/* Destroy the IP to GUID map first. */
|
||
|
DestroyIPToGUIDMap();
|
||
|
|
||
|
fInitialized = FALSE;
|
||
|
|
||
|
end:
|
||
|
|
||
|
LeaveCriticalSection(&csConnectionNotify);
|
||
|
|
||
|
TRACE_VERB("<- %!FUNC! return status = 0x%x", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: WlbsConnectionNotify
|
||
|
* Description: Used to notify the WLBS load module that a connection has been established, reset or closed.
|
||
|
* Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
|
||
|
* Author: shouse 6.13.00
|
||
|
* Notes: All tuple parameters (IPs, ports and protocols) are expected in NETWORK BYTE ORDER.
|
||
|
*/
|
||
|
DWORD WINAPI WlbsConnectionNotify (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, NLB_OPTIONS_CONN_NOTIFICATION_OPERATION Operation, PULONG NLBStatusEx) {
|
||
|
TRACE_VERB("->%!FUNC! server ip 0x%lx, server port %d, client ip 0x%lx, client port %d", ServerIp, ServerPort, ClientIp, ClientPort);
|
||
|
|
||
|
IOCTL_LOCAL_HDR Header;
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
PWCHAR pszAdapterGUID = NULL;
|
||
|
HANDLE hDescriptor;
|
||
|
DWORD dwLength = 0;
|
||
|
HRESULT hresult;
|
||
|
|
||
|
EnterCriticalSection(&csConnectionNotify);
|
||
|
|
||
|
/* By default, the extended NLB status is success. */
|
||
|
*NLBStatusEx = ERROR_SUCCESS;
|
||
|
|
||
|
/* If not done so already, initialize connection notification support. */
|
||
|
if (!fInitialized) {
|
||
|
if ((dwError = WlbsConnectionNotificationInit()) != ERROR_SUCCESS) {
|
||
|
LeaveCriticalSection(&csConnectionNotify);
|
||
|
TRACE_CRIT("%!FUNC! initializing connection notification failed with %d", dwError);
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
fInitialized = TRUE;
|
||
|
}
|
||
|
|
||
|
/* Zero the IOCTL input and output buffers. */
|
||
|
ZeroMemory((VOID *)&Header, sizeof(IOCTL_LOCAL_HDR));
|
||
|
|
||
|
/* Resolve any changes to the IP address table before we map this IP address. */
|
||
|
if ((dwError = ResolveAddressTableChanges()) != ERROR_SUCCESS) {
|
||
|
//
|
||
|
// WlbsCancelConnectionNotify will also enter the critical section, but this is legal. A
|
||
|
// thread that owns the critical section can enter it multiple times without blocking itself.
|
||
|
// However, it must leave the critical section an equal number of times before another
|
||
|
// thread can enter.
|
||
|
//
|
||
|
(void) WlbsCancelConnectionNotify();
|
||
|
LeaveCriticalSection(&csConnectionNotify);
|
||
|
TRACE_CRIT("%!FUNC! resolve ip addresses failed with %d", dwError);
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Retrieve the GUID corresponding to the adapter on which this IP address is configured. */
|
||
|
if (!(pszAdapterGUID = GetGUIDFromIP(ServerIp))) {
|
||
|
(void) WlbsCancelConnectionNotify();
|
||
|
dwError = ERROR_INCORRECT_ADDRESS;
|
||
|
LeaveCriticalSection(&csConnectionNotify);
|
||
|
TRACE_CRIT("%!FUNC! retrieve guid failed with %d", dwError);
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Copy the GUID into the IOCTL input buffer. */
|
||
|
hresult = StringCbCopy(Header.device_name, sizeof(Header.device_name), pszAdapterGUID);
|
||
|
if (FAILED(hresult))
|
||
|
{
|
||
|
(void) WlbsCancelConnectionNotify();
|
||
|
dwError = HRESULT_CODE(hresult);
|
||
|
LeaveCriticalSection(&csConnectionNotify);
|
||
|
TRACE_CRIT("%!FUNC! StringCbCopy failed, Error code : 0x%x", dwError);
|
||
|
TRACE_VERB("<-%!FUNC! return 0x%x", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&csConnectionNotify);
|
||
|
|
||
|
/* Copy the function parameters into the IOCTL input buffer. */
|
||
|
Header.options.notification.flags = 0;
|
||
|
Header.options.notification.conn.Operation = Operation;
|
||
|
Header.options.notification.conn.ServerIPAddress = ServerIp;
|
||
|
Header.options.notification.conn.ServerPort = ntohs(ServerPort);
|
||
|
Header.options.notification.conn.ClientIPAddress = ClientIp;
|
||
|
Header.options.notification.conn.ClientPort = ntohs(ClientPort);
|
||
|
Header.options.notification.conn.Protocol = (USHORT)Protocol;
|
||
|
|
||
|
PrintIPAddress(ServerIp);
|
||
|
TRACE_VERB("%!FUNC! maps to GUID %ws", Header.device_name);
|
||
|
|
||
|
/* Open the device driver. */
|
||
|
if ((hDescriptor = CreateFile(szDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
|
||
|
dwError = GetLastError();
|
||
|
TRACE_CRIT("%!FUNC! open device driver failed with %d", dwError);
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Use an IOCTL to notify the WLBS driver state change for the connection. */
|
||
|
if (!DeviceIoControl(hDescriptor, IOCTL_CVY_CONNECTION_NOTIFY, &Header, sizeof(IOCTL_LOCAL_HDR), &Header, sizeof(IOCTL_LOCAL_HDR), &dwLength, NULL)) {
|
||
|
dwError = GetLastError();
|
||
|
CloseHandle(hDescriptor);
|
||
|
TRACE_CRIT("%!FUNC! ioctl send failed with %d", dwError);
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/* Make sure the expected number of bytes was returned by the IOCTL. */
|
||
|
if (dwLength != sizeof(IOCTL_LOCAL_HDR)) {
|
||
|
dwError = ERROR_INTERNAL_ERROR;
|
||
|
CloseHandle(hDescriptor);
|
||
|
TRACE_CRIT("%!FUNC! unexpected ioctl header length %d received. Expecting %d", dwLength, sizeof(IOCTL_LOCAL_HDR));
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Extended status can be one of:
|
||
|
|
||
|
IOCTL_CVY_OK (WLBS_OK), if the notification is accepted.
|
||
|
IOCTL_CVY_REQUEST_REFUSED (WLBS_REFUSED), if the notification is rejected.
|
||
|
IOCTL_CVY_BAD_PARAMS (WLBS_BAD_PARAMS), if the arguments are invalid.
|
||
|
IOCTL_CVY_NOT_FOUND (WLBS_NOT_FOUND), if NLB was not bound to the specified adapter.
|
||
|
IOCTL_CVY_GENERIC_FAILURE (WLBS_FAILURE), if a non-specific error occurred.
|
||
|
*/
|
||
|
|
||
|
/* Pass the return code from the driver back to the caller. */
|
||
|
*NLBStatusEx = MapStateFromDriverToApi(Header.ctrl.ret_code);
|
||
|
|
||
|
/* Close the device driver. */
|
||
|
CloseHandle(hDescriptor);
|
||
|
|
||
|
TRACE_VERB("->%!FUNC! return %d", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function:
|
||
|
* Description:
|
||
|
* Returns:
|
||
|
* Author: shouse 6.13.00
|
||
|
*/
|
||
|
DWORD WINAPI WlbsConnectionUp (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, PULONG NLBStatusEx) {
|
||
|
|
||
|
return WlbsConnectionNotify(ServerIp, ServerPort, ClientIp, ClientPort, Protocol, NLB_CONN_UP, NLBStatusEx);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function:
|
||
|
* Description:
|
||
|
* Returns:
|
||
|
* Author: shouse 6.13.00
|
||
|
*/
|
||
|
DWORD WINAPI WlbsConnectionDown (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, PULONG NLBStatusEx) {
|
||
|
|
||
|
return WlbsConnectionNotify(ServerIp, ServerPort, ClientIp, ClientPort, Protocol, NLB_CONN_DOWN, NLBStatusEx);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function:
|
||
|
* Description:
|
||
|
* Returns:
|
||
|
* Author: shouse 6.13.00
|
||
|
*/
|
||
|
DWORD WINAPI WlbsConnectionReset (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, PULONG NLBStatusEx) {
|
||
|
|
||
|
return WlbsConnectionNotify(ServerIp, ServerPort, ClientIp, ClientPort, Protocol, NLB_CONN_RESET, NLBStatusEx);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: WlbsInitializeConnectionNotify
|
||
|
* Description: Uses InitializeCriticalSectionAndSpinCount to preallocate all
|
||
|
* memory associated with locking the critical section. Then
|
||
|
* EnterCriticalSection won't raise a STATUS_INVALID_HANDLE
|
||
|
* exception, which could otherwise occur during low memory
|
||
|
* conditions.
|
||
|
* Returns: dwError - DWORD status = ERROR_SUCCESS if call is successful.
|
||
|
* Author: chrisdar 7.16.02
|
||
|
*/
|
||
|
DWORD WlbsInitializeConnectionNotify()
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
|
||
|
TRACE_VERB("-> %!FUNC!");
|
||
|
|
||
|
if (!InitializeCriticalSectionAndSpinCount(&csConnectionNotify, PREALLOC_CRITSECT_SPIN_COUNT))
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
TRACE_CRIT("%!FUNC! InitializeCriticalSectionAndSpinCount failed with error 0x%x", dwError);
|
||
|
}
|
||
|
|
||
|
TRACE_VERB("<- %!FUNC! return status = 0x%x", dwError);
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Function: WlbsUninitializeConnectionNotify
|
||
|
* Description: Frees memory associated with an initialized critical section.
|
||
|
* Behavior is undefined if critical section is owned when this
|
||
|
* function is called. After calling this function, the critical
|
||
|
* section must be initialized again before it can be used.
|
||
|
* Returns:
|
||
|
* Author: chrisdar 7.16.02
|
||
|
*/
|
||
|
VOID WlbsUninitializeConnectionNotify()
|
||
|
{
|
||
|
TRACE_VERB("-> %!FUNC!");
|
||
|
|
||
|
DeleteCriticalSection(&csConnectionNotify);
|
||
|
|
||
|
TRACE_VERB("<- %!FUNC!");
|
||
|
return;
|
||
|
}
|