Leaked source code of windows server 2003
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.

788 lines
28 KiB

  1. /*
  2. * File: notification.cpp
  3. * Description: Support for connection notification.
  4. * Author: shouse 4.30.01
  5. */
  6. #include "precomp.h"
  7. #include <iphlpapi.h>
  8. #include "debug.h"
  9. #include "notification.tmh"
  10. extern DWORD MapStateFromDriverToApi(DWORD dwDriverState);
  11. /* The length of the IP to GUID hash table. */
  12. #define IP_TO_GUID_HASH 19
  13. /* Loopback IP address. (127.0.0.1) */
  14. #define IP_LOOPBACK_ADDRESS 0x0100007f
  15. /* Spin count mask specifying a preallocated event for use by InitializeCriticalSectionAndSpinCount */
  16. #define PREALLOC_CRITSECT_SPIN_COUNT 0x80000000
  17. /* An Ip to GUID table entry. */
  18. typedef struct IPToGUIDEntry {
  19. ULONG dwIPAddress;
  20. WCHAR szAdapterGUID[CVY_MAX_DEVNAME_LEN];
  21. IPToGUIDEntry * pNext;
  22. } IPToGUIDEntry;
  23. /* The WLBS device - necessary for IOCTLs. */
  24. WCHAR szDevice[CVY_STR_SIZE];
  25. /* The IP to GUID map is an array of linked lists hashed on IP address. */
  26. IPToGUIDEntry * IPToGUIDMap[IP_TO_GUID_HASH];
  27. /* An overlapped structure for IP address change notifications. */
  28. OVERLAPPED AddrChangeOverlapped;
  29. /* A handle for IP address change notifications. */
  30. HANDLE hAddrChangeHandle;
  31. /* A handle for an IP address change event. */
  32. HANDLE hAddrChangeEvent;
  33. /* A preallocated critical section for IP address change notifications to
  34. protect against one thread of execution tearing down notification state
  35. while another is using it. */
  36. CRITICAL_SECTION csConnectionNotify;
  37. /* A boolean to indicate whether or not connection notification has been initialized.
  38. Initialization is performed upon the first call to either WlbsConnectionUp or WlbsConnectionDown. */
  39. static BOOL fInitialized = FALSE;
  40. /*
  41. * Function: GetGUIDFromIP
  42. * Description: Gets the GUID from the IPToGUID table corresponding to the
  43. * the given IP address.
  44. * Returns: If the call succeeds, returns a pointer to the unicode string
  45. * containing the CLSID (GUID). Upon failure, returns NULL.
  46. * Author: shouse 6.15.00
  47. */
  48. WCHAR * GetGUIDFromIP (ULONG IPAddress) {
  49. TRACE_VERB("->%!FUNC!");
  50. IPToGUIDEntry * entry = NULL;
  51. /* Loop through the linked list at the hashed index and return the GUID from the entry
  52. corresponding to the given IP address. */
  53. for (entry = IPToGUIDMap[IPAddress % IP_TO_GUID_HASH]; entry; entry = entry->pNext)
  54. {
  55. if (entry->dwIPAddress == IPAddress)
  56. {
  57. if (NULL != entry->szAdapterGUID) TRACE_VERB("->%!FUNC! return guid %ls", entry->szAdapterGUID);
  58. else TRACE_VERB("->%!FUNC! return guid which is NULL");
  59. return entry->szAdapterGUID;
  60. }
  61. }
  62. /* At this point, we can't find the IP address in the table, so bail. */
  63. TRACE_VERB("<-%!FUNC! return NULL");
  64. return NULL;
  65. }
  66. /*
  67. * Function: GetGUIDFromIndex
  68. * Description: Gets the GUID from the AdaptersInfo table corresponding
  69. * to the given IP address.
  70. * Returns: If the call succeeds, returns a pointer to the string containing
  71. * the adapter name (GUID). Upon failure, returns NULL.
  72. * Author: shouse 6.15.00
  73. */
  74. CHAR * GetGUIDFromIndex (PIP_ADAPTER_INFO pAdapterTable, DWORD dwIndex) {
  75. TRACE_VERB("->%!FUNC!");
  76. PIP_ADAPTER_INFO pAdapterInfo = NULL;
  77. /* Loop through the adapter table looking for the given index. Return the adapter
  78. name for the corresponding index. */
  79. for (pAdapterInfo = pAdapterTable; pAdapterInfo; pAdapterInfo = pAdapterInfo->Next)
  80. {
  81. if (pAdapterInfo->Index == dwIndex)
  82. {
  83. TRACE_VERB("->%!FUNC! return guid %s", pAdapterInfo->AdapterName);
  84. return pAdapterInfo->AdapterName;
  85. }
  86. }
  87. /* If we get this far, we can't find it, so bail. */
  88. TRACE_VERB("<-%!FUNC! return NULL");
  89. return NULL;
  90. }
  91. /*
  92. * Function: PrintIPAddress
  93. * Description: Prints an IP address in dot notation.
  94. * Returns:
  95. * Author: shouse 6.15.00
  96. */
  97. void PrintIPAddress (ULONG IPAddress) {
  98. CHAR szIPAddress[16];
  99. HRESULT hresult;
  100. hresult = StringCbPrintfA(szIPAddress, sizeof(szIPAddress), "%d.%d.%d.%d",
  101. IPAddress & 0x000000ff, (IPAddress & 0x0000ff00) >> 8,
  102. (IPAddress & 0x00ff0000) >> 16, (IPAddress & 0xff000000) >> 24);
  103. if (SUCCEEDED(hresult))
  104. {
  105. TRACE_VERB("%!FUNC! %-15s", szIPAddress);
  106. }
  107. }
  108. /*
  109. * Function: PrintIPToGUIDMap
  110. * Description: Traverses and prints the IPToGUID map.
  111. * Returns:
  112. * Author: shouse 6.15.00
  113. */
  114. void PrintIPToGUIDMap (void) {
  115. IPToGUIDEntry * entry = NULL;
  116. DWORD dwHash;
  117. /* Loop through the linked list at each hashed index and print the IP to GUID mapping. */
  118. for (dwHash = 0; dwHash < IP_TO_GUID_HASH; dwHash++) {
  119. for (entry = IPToGUIDMap[dwHash]; entry; entry = entry->pNext) {
  120. PrintIPAddress(entry->dwIPAddress);
  121. TRACE_VERB("%!FUNC! -> GUID %ws\n", entry->szAdapterGUID);
  122. }
  123. }
  124. }
  125. /*
  126. * Function: DestroyIPToGUIDMap
  127. * Description: Destroys the IPToGUID map.
  128. * Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
  129. * Author: shouse 6.15.00
  130. * Modified: chrisdar 07.23.02 - Changed to return void. If this function fails there isn't
  131. * anything we can do about it. When bailing if HeapFree failed we didn't
  132. * NULL the pointer, hence we had an invalid pointer.
  133. */
  134. void DestroyIPToGUIDMap (void) {
  135. TRACE_VERB("->%!FUNC!");
  136. IPToGUIDEntry * next = NULL;
  137. DWORD dwHash;
  138. /* Loop through all hash indexes. */
  139. for (dwHash = 0; dwHash < IP_TO_GUID_HASH; dwHash++) {
  140. next = IPToGUIDMap[dwHash];
  141. /* Loop through the linked list and free each entry. */
  142. while (next) {
  143. IPToGUIDEntry * entry = NULL;
  144. entry = next;
  145. next = next->pNext;
  146. if (!HeapFree(GetProcessHeap(), 0, entry)) {
  147. //
  148. // Don't abort on error because we need to clean up the whole table.
  149. //
  150. TRACE_CRIT("%!FUNC! memory deallocation failed with %d", GetLastError());
  151. }
  152. entry = NULL;
  153. }
  154. /* Reset the pointer to the head of the list in the array. */
  155. IPToGUIDMap[dwHash] = NULL;
  156. }
  157. TRACE_VERB("<-%!FUNC! return void");
  158. return;
  159. }
  160. /*
  161. * Function: BuildIPToGUIDMap
  162. * Description: Builds the IPToGUID map by first getting information on all adapters and
  163. * then retrieving the map of IP addresses to adapters. Using those tables,
  164. * this constructs a mapping of IP addresses to adapter GUIDs.
  165. * Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
  166. * Author: shouse 6.14.00
  167. * Modified: chrisdar 07.24.02 Free dynamically allocated memory when an error occurs.
  168. * Also no longer ignore failures in strsafe functions as this makes
  169. * the table entries useless.
  170. */
  171. //
  172. // TODO: 24 July 2002 chrisdar
  173. // Three issues need to be fixed in this function:
  174. // 1. Method of allocating memory for output of GetAdaptersInfo can fail if adapter
  175. // list changes between calls. This was seen in testing.
  176. // 2. Same as 1. except for output of GetIpAddrTable.
  177. // 3. Output from GetAdaptersInfo has all of the information needed (except that
  178. // IPs are strings instead of dwords). Remove calls to GetIpAddrTable and modify
  179. // logic to use output of GetAdaptersInfo.
  180. //
  181. DWORD BuildIPToGUIDMap (void) {
  182. TRACE_VERB("->%!FUNC!");
  183. DWORD dwError = ERROR_SUCCESS;
  184. PMIB_IPADDRTABLE pAddressTable = NULL;
  185. PIP_ADAPTER_INFO pAdapterTable = NULL;
  186. DWORD dwAddressSize = 0;
  187. DWORD dwAdapterSize = 0;
  188. DWORD dwEntry;
  189. HRESULT hresult;
  190. /* Destroy the IP to GUID map first. */
  191. DestroyIPToGUIDMap();
  192. /* Query the necessary length of a buffer to hold the adapter info. */
  193. if ((dwError = GetAdaptersInfo(pAdapterTable, &dwAdapterSize)) != ERROR_BUFFER_OVERFLOW) {
  194. TRACE_CRIT("%!FUNC! GetAdaptersInfo for buffer size failed with %d", dwError);
  195. goto exit;
  196. }
  197. /* Allocate a buffer of the indicated size. */
  198. if (!(pAdapterTable = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(), 0, dwAdapterSize))) {
  199. dwError = ERROR_NOT_ENOUGH_MEMORY;
  200. TRACE_CRIT("%!FUNC! memory allocation for adapter table failed with %d", dwError);
  201. goto exit;
  202. }
  203. /* Fill the buffer with the adapter info. */
  204. if ((dwError = GetAdaptersInfo(pAdapterTable, &dwAdapterSize)) != NO_ERROR) {
  205. TRACE_CRIT("%!FUNC! GetAdaptersInfo for filling adapter buffer failed with %d", dwError);
  206. goto exit;
  207. }
  208. /* Query the necessary length of a buffer to hold the IP address table. */
  209. if ((dwError = GetIpAddrTable(pAddressTable, &dwAddressSize, TRUE)) != ERROR_INSUFFICIENT_BUFFER) {
  210. TRACE_CRIT("%!FUNC! GetIpAddrTable for IP address length failed with %d", dwError);
  211. goto exit;
  212. }
  213. /* Allocate a buffer of the indicated size. */
  214. if (!(pAddressTable = (PMIB_IPADDRTABLE)HeapAlloc(GetProcessHeap(), 0, dwAddressSize))) {
  215. dwError = ERROR_NOT_ENOUGH_MEMORY;
  216. TRACE_CRIT("%!FUNC! memory allocation for IP address failed with %d", dwError);
  217. goto exit;
  218. }
  219. /* Fill the buffer with the IP address table. */
  220. if ((dwError = GetIpAddrTable(pAddressTable, &dwAddressSize, TRUE)) != NO_ERROR) {
  221. TRACE_CRIT("%!FUNC! GetIpAddrTable for filling IP address buffer failed with %d", dwError);
  222. goto exit;
  223. }
  224. /* For each entry in the IP address to adapter table, create an entry for our IP address to GUID table. */
  225. for (dwEntry = 0; dwEntry < pAddressTable->dwNumEntries; dwEntry++) {
  226. PCHAR pszDeviceName = NULL;
  227. IPToGUIDEntry * entry = NULL;
  228. /* Only create an entry if the IP address is nonzero and is not the IP loopback address. */
  229. if ((pAddressTable->table[dwEntry].dwAddr != 0UL) && (pAddressTable->table[dwEntry].dwAddr != IP_LOOPBACK_ADDRESS)) {
  230. WCHAR szAdapterGUID[CVY_MAX_DEVNAME_LEN];
  231. /* Retrieve the GUID from the interface index. */
  232. if (!(pszDeviceName = GetGUIDFromIndex(pAdapterTable, pAddressTable->table[dwEntry].dwIndex))) {
  233. dwError = ERROR_INCORRECT_ADDRESS;
  234. TRACE_CRIT("%!FUNC! failed retriving interface index from guid with %d", dwError);
  235. goto exit;
  236. }
  237. /* Allocate a buffer for the IP to GUID entry. */
  238. if (!(entry = (IPToGUIDEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(IPToGUIDEntry)))) {
  239. dwError = ERROR_NOT_ENOUGH_MEMORY;
  240. TRACE_CRIT("%!FUNC! memory allocation failure for the IP to guid entry");
  241. goto exit;
  242. }
  243. /* Zero the entry contents. */
  244. ZeroMemory((VOID *)entry, sizeof(entry));
  245. /* Insert the entry at the head of the linked list indexed by the IP address % HASH. */
  246. entry->pNext = IPToGUIDMap[pAddressTable->table[dwEntry].dwAddr % IP_TO_GUID_HASH];
  247. IPToGUIDMap[pAddressTable->table[dwEntry].dwAddr % IP_TO_GUID_HASH] = entry;
  248. /* Fill in the IP address. */
  249. entry->dwIPAddress = pAddressTable->table[dwEntry].dwAddr;
  250. /* GUIDS in NLB multi-NIC are expected to be prefixed with "\DEVICE\". */
  251. hresult = StringCbCopy(entry->szAdapterGUID, sizeof(entry->szAdapterGUID), L"\\DEVICE\\");
  252. if (FAILED(hresult))
  253. {
  254. dwError = (DWORD) hresult;
  255. TRACE_CRIT("%!FUNC! string copy failed for DEVICE, Error code : 0x%x", HRESULT_CODE(hresult));
  256. goto exit;
  257. }
  258. /* Convert the adapter name ASCII string to a GUID unicode string and place it in the table entry. */
  259. if (!MultiByteToWideChar(CP_ACP, 0, pszDeviceName, -1, szAdapterGUID, CVY_MAX_DEVNAME_LEN)) {
  260. dwError = GetLastError();
  261. TRACE_CRIT("%!FUNC! converting ascii string to guid failed with %d", dwError);
  262. goto exit;
  263. }
  264. /* Cat the GUID onto the "\DEVICE\". */
  265. hresult = StringCbCat(entry->szAdapterGUID, sizeof(entry->szAdapterGUID), szAdapterGUID);
  266. if (FAILED(hresult))
  267. {
  268. dwError = (DWORD) hresult;
  269. TRACE_CRIT("%!FUNC! string append of guid failed, Error code : 0x%x", HRESULT_CODE(hresult));
  270. goto exit;
  271. }
  272. }
  273. else
  274. {
  275. TRACE_INFO("%!FUNC! IP address passed is either 0 or localhost. Skipping it.");
  276. }
  277. }
  278. //
  279. // Note that this printing is for debug purposes only. It is left enabled in all builds because it
  280. // only calls TRACE_VERB for ouput.
  281. //
  282. PrintIPToGUIDMap();
  283. exit:
  284. /* Free the buffers used to query the IP stack. */
  285. if (pAddressTable) HeapFree(GetProcessHeap(), 0, pAddressTable);
  286. if (pAdapterTable) HeapFree(GetProcessHeap(), 0, pAdapterTable);
  287. TRACE_VERB("<-%!FUNC! return %d", dwError);
  288. return dwError;
  289. }
  290. /*
  291. * Function: WlbsConnectionNotificationInit
  292. * Description: Initialize connection notification by retrieving the device driver
  293. * information for later use by IOCTLs and build the IPToGUID map.
  294. * Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
  295. * Author: shouse 6.15.00
  296. */
  297. DWORD WlbsConnectionNotificationInit (void) {
  298. TRACE_VERB("->%!FUNC!");
  299. DWORD dwError = ERROR_SUCCESS;
  300. WCHAR szDriver[CVY_STR_SIZE];
  301. HRESULT hresult;
  302. hresult = StringCbPrintf(szDevice, sizeof(szDevice), L"\\\\.\\%ls", CVY_NAME);
  303. if (FAILED(hresult))
  304. {
  305. dwError = HRESULT_CODE(hresult);
  306. TRACE_CRIT("%!FUNC! StringCbPrintf failed, Error code : 0x%x", dwError);
  307. TRACE_VERB("<-%!FUNC! return 0x%x", dwError);
  308. return dwError;
  309. }
  310. /* Query for the existence of the WLBS driver. */
  311. if (!QueryDosDevice(szDevice + 4, szDriver, CVY_STR_SIZE)) {
  312. dwError = GetLastError();
  313. TRACE_CRIT("%!FUNC! querying for nlb driver failed with %d", dwError);
  314. TRACE_VERB("<-%!FUNC! return %d", dwError);
  315. return dwError;
  316. }
  317. /* Build the IP to GUID mapping. */
  318. if ((dwError = BuildIPToGUIDMap()) != ERROR_SUCCESS) {
  319. TRACE_CRIT("%!FUNC! ip to guid map failed with %d", dwError);
  320. TRACE_VERB("<-%!FUNC! return %d", dwError);
  321. return dwError;
  322. }
  323. /* Create an IP address change event. */
  324. if (!(hAddrChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) {
  325. dwError = GetLastError();
  326. TRACE_CRIT("%!FUNC! create event failed with %d", dwError);
  327. TRACE_VERB("<-%!FUNC! return %d", dwError);
  328. return dwError;
  329. }
  330. /* Clear the overlapped structure. */
  331. ZeroMemory(&AddrChangeOverlapped, sizeof(OVERLAPPED));
  332. /* Place the event handle in the overlapped structure. */
  333. AddrChangeOverlapped.hEvent = hAddrChangeEvent;
  334. /* Tell IP to notify us of any changes to the IP address to interface mapping. */
  335. dwError = NotifyAddrChange(&hAddrChangeHandle, &AddrChangeOverlapped);
  336. if ((dwError != NO_ERROR) && (dwError != ERROR_IO_PENDING)) {
  337. TRACE_CRIT("%!FUNC! register of event with ip failed with %d", dwError);
  338. TRACE_VERB("<-%!FUNC! return %d", dwError);
  339. return dwError;
  340. }
  341. TRACE_VERB("<-%!FUNC! return %d", ERROR_SUCCESS);
  342. return ERROR_SUCCESS;
  343. }
  344. /*
  345. * Function: ResolveAddressTableChanges
  346. * Description: Checks for changes in the IP address to adapter mapping and rebuilds the
  347. * IPToGUID map if necessary.
  348. * Returns: Returns ERROR_SUCCESS upon success. Returns an error code otherwise.
  349. * Author: shouse 6.20.00
  350. */
  351. DWORD ResolveAddressTableChanges (void) {
  352. TRACE_VERB("->%!FUNC!");
  353. DWORD dwError = ERROR_SUCCESS;
  354. DWORD dwLength = 0;
  355. /* Check to see if the IP address to adapter table has been modified. */
  356. if (GetOverlappedResult(hAddrChangeHandle, &AddrChangeOverlapped, &dwLength, FALSE)) {
  357. TRACE_INFO("%!FUNC! IP address to adapter table modified... Rebuilding IP to GUID map...");
  358. /* If so, rebuild the IP address to GUID mapping. */
  359. if ((dwError = BuildIPToGUIDMap()) != ERROR_SUCCESS) {
  360. TRACE_CRIT("%!FUNC! ip to guid map failed with %d", dwError);
  361. goto exit;
  362. }
  363. /* Tell IP to notify us of any changes to the IP address to interface mapping. */
  364. dwError = NotifyAddrChange(&hAddrChangeHandle, &AddrChangeOverlapped);
  365. if ((dwError == NO_ERROR) || (dwError == ERROR_IO_PENDING))
  366. {
  367. dwError = ERROR_SUCCESS;
  368. }
  369. else
  370. {
  371. TRACE_CRIT("%!FUNC! register of event with ip failed with %d", dwError);
  372. goto exit;
  373. }
  374. }
  375. else
  376. {
  377. dwError = GetLastError();
  378. if (dwError == ERROR_IO_PENDING || dwError == ERROR_IO_INCOMPLETE)
  379. {
  380. dwError = ERROR_SUCCESS;
  381. }
  382. else
  383. {
  384. TRACE_CRIT("%!FUNC! GetOverlappedResult failed with %d", dwError);
  385. goto exit;
  386. }
  387. }
  388. exit:
  389. TRACE_VERB("->%!FUNC! return %d", dwError);
  390. return dwError;
  391. }
  392. /*
  393. * Function: MapExtendedStatusToWin32
  394. * Description: Converts the status code returned by the driver into a Win32 error code defined in winerror.h.
  395. * Returns: A Win32 error code.
  396. * Author: shouse, 9.7.01
  397. * Notes:
  398. */
  399. DWORD MapExtendedStatusToWin32 (DWORD dwDriverState) {
  400. struct STATE_MAP {
  401. DWORD dwDriverState;
  402. DWORD dwApiState;
  403. } StateMap[] = {
  404. {IOCTL_CVY_BAD_PARAMS, ERROR_INVALID_PARAMETER},
  405. {IOCTL_CVY_NOT_FOUND, ERROR_NOT_FOUND},
  406. {IOCTL_CVY_GENERIC_FAILURE, ERROR_GEN_FAILURE},
  407. {IOCTL_CVY_REQUEST_REFUSED, ERROR_REQUEST_REFUSED},
  408. {IOCTL_CVY_OK, ERROR_SUCCESS}
  409. };
  410. for (int i = 0; i < sizeof(StateMap) / sizeof(StateMap[0]); i++) {
  411. if (StateMap[i].dwDriverState == dwDriverState)
  412. return StateMap[i].dwApiState;
  413. }
  414. /* If we can't find the appropriate driver error code in the map, return failure. */
  415. return ERROR_GEN_FAILURE;
  416. }
  417. /*
  418. * Function: WlbsCancelConnectionNotify
  419. * Description: Cancel IP route and address change notifications from TCP/IP. Call this once after any call to WlbsConnectionNotify.
  420. * Returns: dwError - DWORD status = ERROR_SUCCESS if call is successful.
  421. * Author: chrisdar 7.16.02
  422. */
  423. DWORD WINAPI WlbsCancelConnectionNotify()
  424. {
  425. DWORD dwError = ERROR_SUCCESS;
  426. TRACE_VERB("-> %!FUNC!");
  427. EnterCriticalSection(&csConnectionNotify);
  428. if (!fInitialized)
  429. {
  430. TRACE_VERB("%!FUNC! notification cleanup is not needed...exiting.");
  431. goto end;
  432. }
  433. if (CancelIPChangeNotify(&AddrChangeOverlapped))
  434. {
  435. DWORD BytesTrans;
  436. //
  437. // Block until the cancel operation completes
  438. //
  439. if (!GetOverlappedResult(&hAddrChangeHandle, &AddrChangeOverlapped, &BytesTrans, TRUE))
  440. {
  441. dwError = GetLastError();
  442. if (dwError == ERROR_OPERATION_ABORTED)
  443. {
  444. //
  445. // This is the expected status since we canceled IP change notifications. Overwrite with success for caller.
  446. //
  447. dwError = ERROR_SUCCESS;
  448. }
  449. else
  450. {
  451. TRACE_CRIT("%!FUNC! GetOverlappedResult failed with error 0x%x", dwError);
  452. }
  453. }
  454. }
  455. else
  456. {
  457. //
  458. // Failure conditions are:
  459. // Requested operation already in progress
  460. // There is no notification to cancel
  461. // Neither is a critical error but tell the user about it since this shouldn't happen.
  462. //
  463. dwError = GetLastError();
  464. TRACE_INFO("%!FUNC! CancelIPChangeNotify failed with error 0x%x", dwError);
  465. }
  466. if (!CloseHandle(hAddrChangeEvent))
  467. {
  468. //
  469. // Don't return this status to caller. Just absorb it.
  470. //
  471. TRACE_CRIT("%!FUNC! CloseHandle failed with error 0x%x", GetLastError());
  472. }
  473. hAddrChangeEvent = INVALID_HANDLE_VALUE;
  474. AddrChangeOverlapped.hEvent = INVALID_HANDLE_VALUE;
  475. /* Destroy the IP to GUID map first. */
  476. DestroyIPToGUIDMap();
  477. fInitialized = FALSE;
  478. end:
  479. LeaveCriticalSection(&csConnectionNotify);
  480. TRACE_VERB("<- %!FUNC! return status = 0x%x", dwError);
  481. return dwError;
  482. }
  483. /*
  484. * Function: WlbsConnectionNotify
  485. * Description: Used to notify the WLBS load module that a connection has been established, reset or closed.
  486. * Returns: Returns ERROR_SUCCESS if successful. Returns an error code otherwise.
  487. * Author: shouse 6.13.00
  488. * Notes: All tuple parameters (IPs, ports and protocols) are expected in NETWORK BYTE ORDER.
  489. */
  490. DWORD WINAPI WlbsConnectionNotify (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, NLB_OPTIONS_CONN_NOTIFICATION_OPERATION Operation, PULONG NLBStatusEx) {
  491. TRACE_VERB("->%!FUNC! server ip 0x%lx, server port %d, client ip 0x%lx, client port %d", ServerIp, ServerPort, ClientIp, ClientPort);
  492. IOCTL_LOCAL_HDR Header;
  493. DWORD dwError = ERROR_SUCCESS;
  494. PWCHAR pszAdapterGUID = NULL;
  495. HANDLE hDescriptor;
  496. DWORD dwLength = 0;
  497. HRESULT hresult;
  498. EnterCriticalSection(&csConnectionNotify);
  499. /* By default, the extended NLB status is success. */
  500. *NLBStatusEx = ERROR_SUCCESS;
  501. /* If not done so already, initialize connection notification support. */
  502. if (!fInitialized) {
  503. if ((dwError = WlbsConnectionNotificationInit()) != ERROR_SUCCESS) {
  504. LeaveCriticalSection(&csConnectionNotify);
  505. TRACE_CRIT("%!FUNC! initializing connection notification failed with %d", dwError);
  506. TRACE_VERB("->%!FUNC! return %d", dwError);
  507. return dwError;
  508. }
  509. fInitialized = TRUE;
  510. }
  511. /* Zero the IOCTL input and output buffers. */
  512. ZeroMemory((VOID *)&Header, sizeof(IOCTL_LOCAL_HDR));
  513. /* Resolve any changes to the IP address table before we map this IP address. */
  514. if ((dwError = ResolveAddressTableChanges()) != ERROR_SUCCESS) {
  515. //
  516. // WlbsCancelConnectionNotify will also enter the critical section, but this is legal. A
  517. // thread that owns the critical section can enter it multiple times without blocking itself.
  518. // However, it must leave the critical section an equal number of times before another
  519. // thread can enter.
  520. //
  521. (void) WlbsCancelConnectionNotify();
  522. LeaveCriticalSection(&csConnectionNotify);
  523. TRACE_CRIT("%!FUNC! resolve ip addresses failed with %d", dwError);
  524. TRACE_VERB("->%!FUNC! return %d", dwError);
  525. return dwError;
  526. }
  527. /* Retrieve the GUID corresponding to the adapter on which this IP address is configured. */
  528. if (!(pszAdapterGUID = GetGUIDFromIP(ServerIp))) {
  529. (void) WlbsCancelConnectionNotify();
  530. dwError = ERROR_INCORRECT_ADDRESS;
  531. LeaveCriticalSection(&csConnectionNotify);
  532. TRACE_CRIT("%!FUNC! retrieve guid failed with %d", dwError);
  533. TRACE_VERB("->%!FUNC! return %d", dwError);
  534. return dwError;
  535. }
  536. /* Copy the GUID into the IOCTL input buffer. */
  537. hresult = StringCbCopy(Header.device_name, sizeof(Header.device_name), pszAdapterGUID);
  538. if (FAILED(hresult))
  539. {
  540. (void) WlbsCancelConnectionNotify();
  541. dwError = HRESULT_CODE(hresult);
  542. LeaveCriticalSection(&csConnectionNotify);
  543. TRACE_CRIT("%!FUNC! StringCbCopy failed, Error code : 0x%x", dwError);
  544. TRACE_VERB("<-%!FUNC! return 0x%x", dwError);
  545. return dwError;
  546. }
  547. LeaveCriticalSection(&csConnectionNotify);
  548. /* Copy the function parameters into the IOCTL input buffer. */
  549. Header.options.notification.flags = 0;
  550. Header.options.notification.conn.Operation = Operation;
  551. Header.options.notification.conn.ServerIPAddress = ServerIp;
  552. Header.options.notification.conn.ServerPort = ntohs(ServerPort);
  553. Header.options.notification.conn.ClientIPAddress = ClientIp;
  554. Header.options.notification.conn.ClientPort = ntohs(ClientPort);
  555. Header.options.notification.conn.Protocol = (USHORT)Protocol;
  556. PrintIPAddress(ServerIp);
  557. TRACE_VERB("%!FUNC! maps to GUID %ws", Header.device_name);
  558. /* Open the device driver. */
  559. if ((hDescriptor = CreateFile(szDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
  560. dwError = GetLastError();
  561. TRACE_CRIT("%!FUNC! open device driver failed with %d", dwError);
  562. TRACE_VERB("->%!FUNC! return %d", dwError);
  563. return dwError;
  564. }
  565. /* Use an IOCTL to notify the WLBS driver state change for the connection. */
  566. if (!DeviceIoControl(hDescriptor, IOCTL_CVY_CONNECTION_NOTIFY, &Header, sizeof(IOCTL_LOCAL_HDR), &Header, sizeof(IOCTL_LOCAL_HDR), &dwLength, NULL)) {
  567. dwError = GetLastError();
  568. CloseHandle(hDescriptor);
  569. TRACE_CRIT("%!FUNC! ioctl send failed with %d", dwError);
  570. TRACE_VERB("->%!FUNC! return %d", dwError);
  571. return dwError;
  572. }
  573. /* Make sure the expected number of bytes was returned by the IOCTL. */
  574. if (dwLength != sizeof(IOCTL_LOCAL_HDR)) {
  575. dwError = ERROR_INTERNAL_ERROR;
  576. CloseHandle(hDescriptor);
  577. TRACE_CRIT("%!FUNC! unexpected ioctl header length %d received. Expecting %d", dwLength, sizeof(IOCTL_LOCAL_HDR));
  578. TRACE_VERB("->%!FUNC! return %d", dwError);
  579. return dwError;
  580. }
  581. /*
  582. Extended status can be one of:
  583. IOCTL_CVY_OK (WLBS_OK), if the notification is accepted.
  584. IOCTL_CVY_REQUEST_REFUSED (WLBS_REFUSED), if the notification is rejected.
  585. IOCTL_CVY_BAD_PARAMS (WLBS_BAD_PARAMS), if the arguments are invalid.
  586. IOCTL_CVY_NOT_FOUND (WLBS_NOT_FOUND), if NLB was not bound to the specified adapter.
  587. IOCTL_CVY_GENERIC_FAILURE (WLBS_FAILURE), if a non-specific error occurred.
  588. */
  589. /* Pass the return code from the driver back to the caller. */
  590. *NLBStatusEx = MapStateFromDriverToApi(Header.ctrl.ret_code);
  591. /* Close the device driver. */
  592. CloseHandle(hDescriptor);
  593. TRACE_VERB("->%!FUNC! return %d", dwError);
  594. return dwError;
  595. }
  596. /*
  597. * Function:
  598. * Description:
  599. * Returns:
  600. * Author: shouse 6.13.00
  601. */
  602. DWORD WINAPI WlbsConnectionUp (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, PULONG NLBStatusEx) {
  603. return WlbsConnectionNotify(ServerIp, ServerPort, ClientIp, ClientPort, Protocol, NLB_CONN_UP, NLBStatusEx);
  604. }
  605. /*
  606. * Function:
  607. * Description:
  608. * Returns:
  609. * Author: shouse 6.13.00
  610. */
  611. DWORD WINAPI WlbsConnectionDown (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, PULONG NLBStatusEx) {
  612. return WlbsConnectionNotify(ServerIp, ServerPort, ClientIp, ClientPort, Protocol, NLB_CONN_DOWN, NLBStatusEx);
  613. }
  614. /*
  615. * Function:
  616. * Description:
  617. * Returns:
  618. * Author: shouse 6.13.00
  619. */
  620. DWORD WINAPI WlbsConnectionReset (ULONG ServerIp, USHORT ServerPort, ULONG ClientIp, USHORT ClientPort, BYTE Protocol, PULONG NLBStatusEx) {
  621. return WlbsConnectionNotify(ServerIp, ServerPort, ClientIp, ClientPort, Protocol, NLB_CONN_RESET, NLBStatusEx);
  622. }
  623. /*
  624. * Function: WlbsInitializeConnectionNotify
  625. * Description: Uses InitializeCriticalSectionAndSpinCount to preallocate all
  626. * memory associated with locking the critical section. Then
  627. * EnterCriticalSection won't raise a STATUS_INVALID_HANDLE
  628. * exception, which could otherwise occur during low memory
  629. * conditions.
  630. * Returns: dwError - DWORD status = ERROR_SUCCESS if call is successful.
  631. * Author: chrisdar 7.16.02
  632. */
  633. DWORD WlbsInitializeConnectionNotify()
  634. {
  635. DWORD dwError = ERROR_SUCCESS;
  636. TRACE_VERB("-> %!FUNC!");
  637. if (!InitializeCriticalSectionAndSpinCount(&csConnectionNotify, PREALLOC_CRITSECT_SPIN_COUNT))
  638. {
  639. dwError = GetLastError();
  640. TRACE_CRIT("%!FUNC! InitializeCriticalSectionAndSpinCount failed with error 0x%x", dwError);
  641. }
  642. TRACE_VERB("<- %!FUNC! return status = 0x%x", dwError);
  643. return dwError;
  644. }
  645. /*
  646. * Function: WlbsUninitializeConnectionNotify
  647. * Description: Frees memory associated with an initialized critical section.
  648. * Behavior is undefined if critical section is owned when this
  649. * function is called. After calling this function, the critical
  650. * section must be initialized again before it can be used.
  651. * Returns:
  652. * Author: chrisdar 7.16.02
  653. */
  654. VOID WlbsUninitializeConnectionNotify()
  655. {
  656. TRACE_VERB("-> %!FUNC!");
  657. DeleteCriticalSection(&csConnectionNotify);
  658. TRACE_VERB("<- %!FUNC!");
  659. return;
  660. }