Source code of Windows XP (NT5)
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.

1736 lines
46 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cxpnp.c
  5. Abstract:
  6. PnP handling code for the Cluster Network Driver.
  7. Author:
  8. Mike Massa (mikemas) March 21, 1998
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 03-22-98 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #include <ntddk.h>
  17. #include <wmistr.h>
  18. #include <ndisguid.h>
  19. #include <ntddndis.h>
  20. #include <ntpnpapi.h>
  21. #include <zwapi.h>
  22. #pragma hdrstop
  23. #include "cxpnp.tmh"
  24. //
  25. // Local data structures
  26. //
  27. typedef struct _CNP_WMI_RECONNECT_WORKER_CONTEXT {
  28. PIO_WORKITEM WorkItem;
  29. CL_NETWORK_ID NetworkId;
  30. } CNP_WMI_RECONNECT_WORKER_CONTEXT, *PCNP_WMI_RECONNECT_WORKER_CONTEXT;
  31. //
  32. // WMI Data
  33. //
  34. PERESOURCE CnpWmiNdisMediaStatusResource = NULL;
  35. PVOID CnpWmiNdisMediaStatusConnectObject = NULL;
  36. PVOID CnpWmiNdisMediaStatusDisconnectObject = NULL;
  37. HANDLE CnpIpMediaSenseFileHandle = NULL;
  38. PIRP CnpIpDisableMediaSenseIrp = NULL;
  39. PKEVENT CnpIpDisableMediaSenseEvent = NULL;
  40. //
  41. // Local prototypes
  42. //
  43. NTSTATUS
  44. CnpWmiPnpDisableMediaSenseCompletion(
  45. IN PDEVICE_OBJECT DeviceObject,
  46. IN PIRP Irp,
  47. IN PVOID Context
  48. );
  49. VOID
  50. CnpWmiNdisMediaStatusConnectCallback(
  51. IN PVOID Wnode,
  52. IN PVOID Context
  53. );
  54. VOID
  55. CnpWmiNdisMediaStatusDisconnectCallback(
  56. IN PVOID Wnode,
  57. IN PVOID Context
  58. );
  59. VOID
  60. CnpReconnectLocalInterfaceWrapper(
  61. IN PDEVICE_OBJECT DeviceObject,
  62. IN PVOID Context
  63. );
  64. VOID
  65. CnpDisconnectLocalInterface(
  66. PCNP_INTERFACE Interface,
  67. PCNP_NETWORK Network
  68. );
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text(INIT, CxWmiPnpLoad)
  71. #pragma alloc_text(PAGE, CxWmiPnpUnload)
  72. #pragma alloc_text(PAGE, CxWmiPnpInitialize)
  73. #pragma alloc_text(PAGE, CxWmiPnpShutdown)
  74. #endif // ALLOC_PRAGMA
  75. //
  76. // Exported Routines
  77. //
  78. VOID
  79. CxTdiAddAddressHandler(
  80. IN PTA_ADDRESS TaAddress,
  81. IN PUNICODE_STRING DeviceName,
  82. IN PTDI_PNP_CONTEXT Context
  83. )
  84. {
  85. if (TaAddress->AddressType == TDI_ADDRESS_TYPE_IP) {
  86. NTSTATUS status;
  87. PTDI_ADDRESS_IP tdiAddressIp = (PTDI_ADDRESS_IP)
  88. &(TaAddress->Address[0]);
  89. IF_CNDBG(CN_DEBUG_CONFIG) {
  90. CNPRINT((
  91. "[CX] Processing PnP add event for IP address %lx\n",
  92. tdiAddressIp->in_addr
  93. ));
  94. }
  95. //
  96. // Ensure that this is a valid address, and that it is not one
  97. // that we brought online for a cluster ip address resource.
  98. //
  99. if (tdiAddressIp->in_addr != 0) {
  100. if (!IpaIsAddressRegistered(tdiAddressIp->in_addr)) {
  101. IF_CNDBG(CN_DEBUG_CONFIG) {
  102. CNPRINT((
  103. "[CX] Issuing address add event to cluster svc for IP address %lx\n",
  104. tdiAddressIp->in_addr
  105. ));
  106. }
  107. CnIssueEvent(
  108. ClusnetEventAddAddress,
  109. 0,
  110. (CL_NETWORK_ID) tdiAddressIp->in_addr
  111. );
  112. }
  113. else {
  114. IF_CNDBG(CN_DEBUG_CONFIG) {
  115. CNPRINT((
  116. "[CX] PnP add event is for an IP address resource, skip.\n"
  117. ));
  118. }
  119. }
  120. }
  121. }
  122. return;
  123. } // CxTdiAddAddressHandler
  124. VOID
  125. CxTdiDelAddressHandler(
  126. IN PTA_ADDRESS TaAddress,
  127. IN PUNICODE_STRING DeviceName,
  128. IN PTDI_PNP_CONTEXT Context
  129. )
  130. {
  131. if (TaAddress->AddressType == TDI_ADDRESS_TYPE_IP) {
  132. NTSTATUS status;
  133. PCNP_INTERFACE interface;
  134. PCNP_NETWORK network;
  135. PLIST_ENTRY entry;
  136. PTA_IP_ADDRESS taIpAddress;
  137. CN_IRQL nodeTableIrql;
  138. CL_NODE_ID i;
  139. PTDI_ADDRESS_IP tdiAddressIp = (PTDI_ADDRESS_IP)
  140. &(TaAddress->Address[0]);
  141. IF_CNDBG(CN_DEBUG_CONFIG) {
  142. CNPRINT((
  143. "[CX] Processing PnP delete event for IP address %lx.\n",
  144. tdiAddressIp->in_addr
  145. ));
  146. }
  147. if (tdiAddressIp->in_addr != 0) {
  148. //
  149. // Figure out if this is the address for one of this node's
  150. // registered interfaces.
  151. //
  152. CnAcquireLock(&CnpNodeTableLock, &nodeTableIrql);
  153. if (CnpLocalNode != NULL) {
  154. CnAcquireLockAtDpc(&(CnpLocalNode->Lock));
  155. CnReleaseLockFromDpc(&CnpNodeTableLock);
  156. CnpLocalNode->Irql = nodeTableIrql;
  157. network = NULL;
  158. for (entry = CnpLocalNode->InterfaceList.Flink;
  159. entry != &(CnpLocalNode->InterfaceList);
  160. entry = entry->Flink
  161. )
  162. {
  163. interface = CONTAINING_RECORD(
  164. entry,
  165. CNP_INTERFACE,
  166. NodeLinkage
  167. );
  168. taIpAddress = (PTA_IP_ADDRESS) &(interface->TdiAddress);
  169. if (taIpAddress->Address[0].Address[0].in_addr ==
  170. tdiAddressIp->in_addr
  171. )
  172. {
  173. //
  174. // Found the local interface corresponding to this
  175. // address. Be proactive - destroy the corresponding
  176. // network now.
  177. //
  178. network = interface->Network;
  179. CnAcquireLockAtDpc(&CnpNetworkListLock);
  180. CnAcquireLockAtDpc(&(network->Lock));
  181. CnReleaseLockFromDpc(&(CnpLocalNode->Lock));
  182. network->Irql = DISPATCH_LEVEL;
  183. IF_CNDBG(CN_DEBUG_CONFIG) {
  184. CNPRINT((
  185. "[CX] Deleting network ID %u after PnP "
  186. "delete event for IP address %lx.\n",
  187. network->Id, tdiAddressIp->in_addr
  188. ));
  189. }
  190. CnpDeleteNetwork(network, nodeTableIrql);
  191. //
  192. // Both locks were released.
  193. //
  194. break;
  195. }
  196. }
  197. if (network == NULL) {
  198. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  199. }
  200. //
  201. // Post an event to the service.
  202. //
  203. CnIssueEvent(
  204. ClusnetEventDelAddress,
  205. 0,
  206. (CL_NETWORK_ID) tdiAddressIp->in_addr
  207. );
  208. }
  209. else {
  210. CnReleaseLock(&CnpNodeTableLock, nodeTableIrql);
  211. }
  212. }
  213. }
  214. return;
  215. } // CxTdiDelAddressHandler
  216. NTSTATUS
  217. CxWmiPnpLoad(
  218. VOID
  219. )
  220. /*++
  221. Notes:
  222. Called when clusnet driver is loaded.
  223. --*/
  224. {
  225. PDEVICE_OBJECT ipDeviceObject = NULL;
  226. PFILE_OBJECT ipFileObject = NULL;
  227. PIO_STACK_LOCATION irpSp;
  228. NTSTATUS status;
  229. //
  230. // Allocate a synchronization resource.
  231. //
  232. CnpWmiNdisMediaStatusResource = CnAllocatePool(sizeof(ERESOURCE));
  233. if (CnpWmiNdisMediaStatusResource == NULL) {
  234. return(STATUS_INSUFFICIENT_RESOURCES);
  235. }
  236. status = ExInitializeResourceLite(CnpWmiNdisMediaStatusResource);
  237. if (!NT_SUCCESS(status)) {
  238. return(status);
  239. }
  240. //
  241. // Get a handle to the IP device object to disable media sense
  242. //
  243. status = CnpOpenDevice(
  244. DD_IP_DEVICE_NAME,
  245. &CnpIpMediaSenseFileHandle
  246. );
  247. if (!NT_SUCCESS(status)) {
  248. IF_CNDBG(CN_DEBUG_INIT) {
  249. CNPRINT(("[CX] Failed to open IP device to "
  250. "disable media sense, status %lx\n",
  251. status));
  252. }
  253. return(status);
  254. }
  255. //
  256. // Disable IP media sense. This works by submitting an
  257. // IOCTL_IP_DISABLE_MEDIA_SENSE_REQUEST IRP. The IRP
  258. // will pend until we cancel it (re-enabling media sense).
  259. //
  260. CnpIpDisableMediaSenseEvent = CnAllocatePool(sizeof(KEVENT));
  261. if (CnpIpDisableMediaSenseEvent != NULL) {
  262. KeInitializeEvent(
  263. CnpIpDisableMediaSenseEvent,
  264. SynchronizationEvent,
  265. FALSE
  266. );
  267. //
  268. // Reference the IP file object and get the device object
  269. //
  270. status = ObReferenceObjectByHandle(
  271. CnpIpMediaSenseFileHandle,
  272. 0,
  273. NULL,
  274. KernelMode,
  275. &ipFileObject,
  276. NULL
  277. );
  278. if (NT_SUCCESS(status)) {
  279. ipDeviceObject = IoGetRelatedDeviceObject(ipFileObject);
  280. //
  281. // File object reference is no longer needed
  282. // because the handle is still open.
  283. //
  284. ObDereferenceObject(ipFileObject);
  285. CnpIpDisableMediaSenseIrp = IoAllocateIrp(
  286. ipDeviceObject->StackSize,
  287. FALSE
  288. );
  289. if (CnpIpDisableMediaSenseIrp != NULL) {
  290. irpSp = IoGetNextIrpStackLocation(CnpIpDisableMediaSenseIrp);
  291. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  292. irpSp->Parameters.DeviceIoControl.IoControlCode
  293. = IOCTL_IP_DISABLE_MEDIA_SENSE_REQUEST;
  294. irpSp->DeviceObject = ipDeviceObject;
  295. irpSp->FileObject = ipFileObject;
  296. IoSetCompletionRoutine(
  297. CnpIpDisableMediaSenseIrp,
  298. CnpWmiPnpDisableMediaSenseCompletion,
  299. NULL,
  300. TRUE,
  301. TRUE,
  302. TRUE
  303. );
  304. status = IoCallDriver(
  305. ipDeviceObject,
  306. CnpIpDisableMediaSenseIrp
  307. );
  308. if (status != STATUS_PENDING) {
  309. IF_CNDBG(CN_DEBUG_INIT) {
  310. CNPRINT(("[CX] Failed to disable IP media "
  311. "sense, status %lx\n", status));
  312. }
  313. KeWaitForSingleObject(
  314. CnpIpDisableMediaSenseEvent,
  315. Executive,
  316. KernelMode,
  317. FALSE,
  318. NULL
  319. );
  320. CnFreePool(CnpIpDisableMediaSenseEvent);
  321. CnpIpDisableMediaSenseEvent = NULL;
  322. IoFreeIrp(CnpIpDisableMediaSenseIrp);
  323. CnpIpDisableMediaSenseIrp = NULL;
  324. //
  325. // Cannot risk simply returning status
  326. // because we need the driver load to
  327. // fail.
  328. //
  329. if (NT_SUCCESS(status)) {
  330. status = STATUS_UNSUCCESSFUL;
  331. }
  332. } else {
  333. //
  334. // Need to return STATUS_SUCCESS so that
  335. // the driver load will not fail.
  336. //
  337. status = STATUS_SUCCESS;
  338. IF_CNDBG(CN_DEBUG_INIT) {
  339. CNPRINT(("[CX] IP media sense disabled.\n"));
  340. }
  341. CnTrace(
  342. CXPNP, CxWmiPnpIPMediaSenseDisabled,
  343. "[CXPNP] IP media sense disabled.\n"
  344. );
  345. }
  346. } else {
  347. IF_CNDBG(CN_DEBUG_INIT) {
  348. CNPRINT(("[CX] Failed to allocate IP media sense "
  349. "disable IRP.\n"));
  350. }
  351. CnFreePool(CnpIpDisableMediaSenseEvent);
  352. CnpIpDisableMediaSenseEvent = NULL;
  353. status = STATUS_INSUFFICIENT_RESOURCES;
  354. }
  355. } else {
  356. IF_CNDBG(CN_DEBUG_INIT) {
  357. CNPRINT(("[CX] Failed to reference IP device "
  358. "file handle, status %lx\n", status));
  359. }
  360. CnFreePool(CnpIpDisableMediaSenseEvent);
  361. CnpIpDisableMediaSenseEvent = NULL;
  362. }
  363. } else {
  364. IF_CNDBG(CN_DEBUG_INIT) {
  365. CNPRINT(("[CX] Failed to allocate IP media sense "
  366. "disable event.\n"));
  367. }
  368. status = STATUS_INSUFFICIENT_RESOURCES;
  369. }
  370. return(status);
  371. } // CxWmiPnpLoad
  372. VOID
  373. CxWmiPnpUnload(
  374. VOID
  375. )
  376. /*++
  377. Notes:
  378. Called when clusnet driver is unloaded.
  379. --*/
  380. {
  381. CnAssert(CnpWmiNdisMediaStatusConnectObject == NULL);
  382. CnAssert(CnpWmiNdisMediaStatusDisconnectObject == NULL);
  383. //
  384. // Re-enable IP media sense. This works by cancelling our
  385. // IOCTL_IP_DISABLE_MEDIA_SENSE_REQUEST IRP, which should
  386. // still be pending.
  387. //
  388. if (CnpIpDisableMediaSenseIrp != NULL) {
  389. if (!IoCancelIrp(CnpIpDisableMediaSenseIrp)) {
  390. //
  391. // Our disable media sense IRP could not be cancelled. This
  392. // probably means that it was completed because somebody
  393. // else submitted a media sense enable request.
  394. //
  395. CnTrace(
  396. CXPNP, CnpWmiPnpDisableMediaSenseCompletionUnexpected,
  397. "[CXPNP] IP media sense re-enabled unexpectedly.\n"
  398. );
  399. } else {
  400. //
  401. // Irp was cancelled, and media sense is disabled as
  402. // expected.
  403. //
  404. CnTrace(
  405. CXPNP, CnpWmiPnpDisableMediaSenseCompletion,
  406. "[CXPNP] IP media sense re-enabled.\n"
  407. );
  408. }
  409. //
  410. // Regardless of who re-enabled media sense, we need to free
  411. // the media sense IRP and event. First we wait on the event,
  412. // which is signalled in our completion routine.
  413. //
  414. KeWaitForSingleObject(
  415. CnpIpDisableMediaSenseEvent,
  416. Executive,
  417. KernelMode,
  418. FALSE,
  419. NULL
  420. );
  421. CnFreePool(CnpIpDisableMediaSenseEvent);
  422. CnpIpDisableMediaSenseEvent = NULL;
  423. IoFreeIrp(CnpIpDisableMediaSenseIrp);
  424. CnpIpDisableMediaSenseIrp = NULL;
  425. }
  426. CnAssert(CnpIpDisableMediaSenseIrp == NULL);
  427. if (CnpIpMediaSenseFileHandle != NULL) {
  428. ZwClose(CnpIpMediaSenseFileHandle);
  429. CnpIpMediaSenseFileHandle = NULL;
  430. }
  431. if (CnpWmiNdisMediaStatusResource != NULL) {
  432. ExDeleteResourceLite(CnpWmiNdisMediaStatusResource);
  433. CnFreePool(CnpWmiNdisMediaStatusResource);
  434. CnpWmiNdisMediaStatusResource = NULL;
  435. }
  436. } // CxWmiPnpUnload
  437. NTSTATUS
  438. CxWmiPnpInitialize(
  439. VOID
  440. )
  441. /*++
  442. Notes:
  443. Called in response to initialize ioctl.
  444. --*/
  445. {
  446. NTSTATUS status = STATUS_SUCCESS;
  447. BOOLEAN acquired = FALSE;
  448. GUID wmiGuid;
  449. PAGED_CODE();
  450. acquired = CnAcquireResourceExclusive(
  451. CnpWmiNdisMediaStatusResource,
  452. TRUE
  453. );
  454. CnAssert(acquired == TRUE);
  455. //
  456. // Register WMI callbacks for NDIS media status events
  457. //
  458. if (CnpWmiNdisMediaStatusConnectObject == NULL) {
  459. wmiGuid = GUID_NDIS_STATUS_MEDIA_CONNECT;
  460. status = IoWMIOpenBlock(
  461. &wmiGuid,
  462. WMIGUID_NOTIFICATION,
  463. &CnpWmiNdisMediaStatusConnectObject
  464. );
  465. if (!NT_SUCCESS(status)) {
  466. CNPRINT((
  467. "[CX] Unable to open WMI NDIS status media connect "
  468. "datablock, status %lx\n",
  469. status
  470. ));
  471. CnpWmiNdisMediaStatusConnectObject = NULL;
  472. goto error_exit;
  473. }
  474. status = IoWMISetNotificationCallback(
  475. CnpWmiNdisMediaStatusConnectObject,
  476. CnpWmiNdisMediaStatusConnectCallback,
  477. NULL
  478. );
  479. if (!NT_SUCCESS(status)) {
  480. CNPRINT((
  481. "[CX] Unable to register WMI NDIS status media connect "
  482. "callback, status %lx\n",
  483. status
  484. ));
  485. goto error_exit;
  486. }
  487. }
  488. if (CnpWmiNdisMediaStatusDisconnectObject == NULL) {
  489. wmiGuid = GUID_NDIS_STATUS_MEDIA_DISCONNECT;
  490. status = IoWMIOpenBlock(
  491. &wmiGuid,
  492. WMIGUID_NOTIFICATION,
  493. &CnpWmiNdisMediaStatusDisconnectObject
  494. );
  495. if (!NT_SUCCESS(status)) {
  496. CNPRINT((
  497. "[CX] Unable to open WMI NDIS status media disconnect "
  498. "datablock, status %lx\n",
  499. status
  500. ));
  501. CnpWmiNdisMediaStatusDisconnectObject = NULL;
  502. goto error_exit;
  503. }
  504. status = IoWMISetNotificationCallback(
  505. CnpWmiNdisMediaStatusDisconnectObject,
  506. CnpWmiNdisMediaStatusDisconnectCallback,
  507. NULL
  508. );
  509. if (!NT_SUCCESS(status)) {
  510. CNPRINT((
  511. "[CX] Unable to register WMI NDIS status media disconnect "
  512. "callback, status %lx\n",
  513. status
  514. ));
  515. goto error_exit;
  516. }
  517. }
  518. goto release_exit;
  519. error_exit:
  520. if (CnpWmiNdisMediaStatusConnectObject != NULL) {
  521. ObDereferenceObject(CnpWmiNdisMediaStatusConnectObject);
  522. CnpWmiNdisMediaStatusConnectObject = NULL;
  523. }
  524. if (CnpWmiNdisMediaStatusDisconnectObject != NULL) {
  525. ObDereferenceObject(CnpWmiNdisMediaStatusDisconnectObject);
  526. CnpWmiNdisMediaStatusDisconnectObject = NULL;
  527. }
  528. release_exit:
  529. //
  530. // Release resource
  531. //
  532. if (acquired) {
  533. CnReleaseResourceForThread(
  534. CnpWmiNdisMediaStatusResource,
  535. (ERESOURCE_THREAD) PsGetCurrentThread()
  536. );
  537. }
  538. return(status);
  539. } // CxWmiPnpInitialize
  540. VOID
  541. CxWmiPnpShutdown(
  542. VOID
  543. )
  544. /*++
  545. Notes:
  546. Called in response to clusnet shutdown.
  547. --*/
  548. {
  549. BOOLEAN acquired = FALSE;
  550. PAGED_CODE();
  551. acquired = CnAcquireResourceExclusive(
  552. CnpWmiNdisMediaStatusResource,
  553. TRUE
  554. );
  555. CnAssert(acquired == TRUE);
  556. if (CnpWmiNdisMediaStatusConnectObject != NULL) {
  557. ObDereferenceObject(CnpWmiNdisMediaStatusConnectObject);
  558. CnpWmiNdisMediaStatusConnectObject = NULL;
  559. }
  560. if (CnpWmiNdisMediaStatusDisconnectObject != NULL) {
  561. ObDereferenceObject(CnpWmiNdisMediaStatusDisconnectObject);
  562. CnpWmiNdisMediaStatusDisconnectObject = NULL;
  563. }
  564. //
  565. // Release resource
  566. //
  567. if (acquired) {
  568. CnReleaseResourceForThread(
  569. CnpWmiNdisMediaStatusResource,
  570. (ERESOURCE_THREAD) PsGetCurrentThread()
  571. );
  572. }
  573. return;
  574. } // CxWmiPnpShutdown
  575. VOID
  576. CxReconnectLocalInterface(
  577. IN CL_NETWORK_ID NetworkId
  578. )
  579. /**
  580. Routine Description:
  581. Queues a worker thread to set the local interface
  582. associated with NetworkId to connected. Called when
  583. a heartbeat is received over a network that is marked
  584. locally disconnected.
  585. Arguments:
  586. NetworkId - network ID of network to be reconnected
  587. Return value:
  588. None
  589. Notes:
  590. Can fail without reporting an error if either
  591. allocation fails.
  592. --*/
  593. {
  594. PCNP_WMI_RECONNECT_WORKER_CONTEXT context;
  595. context = CnAllocatePool(sizeof(CNP_WMI_RECONNECT_WORKER_CONTEXT));
  596. if (context != NULL) {
  597. context->WorkItem = IoAllocateWorkItem(CnDeviceObject);
  598. if (context->WorkItem != NULL) {
  599. context->NetworkId = NetworkId;
  600. CnTrace(
  601. CXPNP, CxReconnectLocalInterface,
  602. "[CXPNP] Queueing worker thread to reconnect local "
  603. "interface for network ID %u.\n",
  604. NetworkId // LOGULONG
  605. );
  606. IoQueueWorkItem(
  607. context->WorkItem,
  608. CnpReconnectLocalInterfaceWrapper,
  609. DelayedWorkQueue,
  610. context
  611. );
  612. } else {
  613. CnFreePool(context);
  614. }
  615. }
  616. return;
  617. }
  618. VOID
  619. CxQueryMediaStatus(
  620. IN HANDLE AdapterDeviceHandle,
  621. IN CL_NETWORK_ID NetworkId,
  622. OUT PULONG MediaStatus
  623. )
  624. /**
  625. Routine Description:
  626. Queries the status of the adapter device. Used to
  627. determine whether a local interface is initially
  628. connected or disconnected.
  629. Arguments:
  630. AdapterHandle - adapter device object handle
  631. NetworkId - network ID of adapter to be queried
  632. Return value:
  633. None
  634. Notes:
  635. NDIS query formation modeled after ndis\lib\ndisapi.c
  636. --*/
  637. {
  638. BOOLEAN acquired = FALSE;
  639. NTSTATUS status;
  640. CnVerifyCpuLockMask(
  641. 0, // Required
  642. 0xFFFFFFFF, // Forbidden
  643. 0 // Maximum
  644. );
  645. //
  646. // Set default
  647. //
  648. *MediaStatus = NdisMediaStateDisconnected;
  649. //
  650. // Acquire resource
  651. //
  652. acquired = CnAcquireResourceExclusive(
  653. CnpWmiNdisMediaStatusResource,
  654. TRUE
  655. );
  656. CnAssert(acquired == TRUE);
  657. if (AdapterDeviceHandle != NULL) {
  658. //
  659. // Construct NDIS statistics query
  660. //
  661. NDIS_OID statsOidList[] =
  662. {
  663. OID_GEN_MEDIA_CONNECT_STATUS // | NDIS_OID_PRIVATE
  664. };
  665. UCHAR statsBuf[
  666. FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data)
  667. + sizeof(LARGE_INTEGER)
  668. ];
  669. PNDIS_STATISTICS_VALUE pStatsBuf;
  670. LARGE_INTEGER value;
  671. IF_CNDBG( CN_DEBUG_CONFIG ) {
  672. CNPRINT((
  673. "[CXPNP] Querying NDIS for local adapter "
  674. "on network %u (handle %p).\n",
  675. NetworkId,
  676. AdapterDeviceHandle
  677. ));
  678. }
  679. pStatsBuf = (PNDIS_STATISTICS_VALUE) &statsBuf[0];
  680. status = CnpZwDeviceControl(
  681. AdapterDeviceHandle,
  682. IOCTL_NDIS_QUERY_SELECTED_STATS,
  683. statsOidList,
  684. sizeof(statsOidList),
  685. pStatsBuf,
  686. sizeof(statsBuf)
  687. );
  688. IF_CNDBG( CN_DEBUG_CONFIG ) {
  689. CNPRINT((
  690. "[CXPNP] NDIS query for local adapter "
  691. "on network %u returned status %lx.\n",
  692. NetworkId,
  693. status
  694. ));
  695. }
  696. if (pStatsBuf->DataLength == sizeof(LARGE_INTEGER)) {
  697. value.QuadPart = *(PULONGLONG)(&pStatsBuf->Data[0]);
  698. } else {
  699. value.LowPart = *(PULONG)(&pStatsBuf->Data[0]);
  700. }
  701. *MediaStatus = value.LowPart; // NdisMediaState{Disc|C}onnected
  702. IF_CNDBG( CN_DEBUG_CONFIG ) {
  703. CNPRINT((
  704. "[CXPNP] NDIS query for local adapter "
  705. "on network %u returned media status %lx.\n",
  706. NetworkId,
  707. *MediaStatus
  708. ));
  709. }
  710. CnTrace(
  711. CXPNP, CxQueryMediaStatus,
  712. "[CXPNP] Found media status %u for local network ID %u.\n",
  713. *MediaStatus, // LOGULONG
  714. NetworkId // LOGULONG
  715. );
  716. }
  717. //
  718. // If the media status is disconnected, we must disconnect the
  719. // local interface and network.
  720. //
  721. if (*MediaStatus == NdisMediaStateDisconnected) {
  722. PCNP_NETWORK network = NULL;
  723. PCNP_INTERFACE interface = NULL;
  724. CN_IRQL nodeTableIrql;
  725. PLIST_ENTRY entry;
  726. CnAcquireLock(&CnpNodeTableLock, &nodeTableIrql);
  727. if (CnpLocalNode != NULL) {
  728. CnAcquireLockAtDpc(&(CnpLocalNode->Lock));
  729. CnReleaseLockFromDpc(&CnpNodeTableLock);
  730. CnpLocalNode->Irql = nodeTableIrql;
  731. network = CnpFindNetwork(NetworkId);
  732. if (network != NULL) {
  733. //
  734. // Only go through the disconnect if the network
  735. // is currently marked as locally connected.
  736. // It is possible that we have already received
  737. // and processed a WMI disconnect event.
  738. //
  739. if (!CnpIsNetworkLocalDisconn(network)) {
  740. for (entry = CnpLocalNode->InterfaceList.Flink;
  741. entry != &(CnpLocalNode->InterfaceList);
  742. entry = entry->Flink
  743. )
  744. {
  745. interface = CONTAINING_RECORD(
  746. entry,
  747. CNP_INTERFACE,
  748. NodeLinkage
  749. );
  750. if (interface->Network == network) {
  751. CnpDisconnectLocalInterface(
  752. interface,
  753. network
  754. );
  755. //
  756. // Both node and network locks
  757. // were released.
  758. //
  759. break;
  760. } else {
  761. interface = NULL;
  762. }
  763. }
  764. } else {
  765. CnTrace(
  766. CXPNP, CxQueryMediaStatusDisconnectRedundant,
  767. "[CXPNP] Network ID %u is already disconnected; "
  768. "aborting disconnect.\n",
  769. network->Id // LOGULONG
  770. );
  771. }
  772. if (interface == NULL) {
  773. CnReleaseLock(&(network->Lock), network->Irql);
  774. }
  775. }
  776. if (interface == NULL) {
  777. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  778. }
  779. } else {
  780. CnReleaseLock(&CnpNodeTableLock, nodeTableIrql);
  781. }
  782. }
  783. //
  784. // Release resource
  785. //
  786. if (acquired) {
  787. CnReleaseResourceForThread(
  788. CnpWmiNdisMediaStatusResource,
  789. (ERESOURCE_THREAD) PsGetCurrentThread()
  790. );
  791. }
  792. CnVerifyCpuLockMask(
  793. 0, // Required
  794. 0xFFFFFFFF, // Forbidden
  795. 0 // Maximum
  796. );
  797. return;
  798. } // CxQueryMediaStatus
  799. //
  800. // Local Routines
  801. //
  802. NTSTATUS
  803. CnpWmiPnpDisableMediaSenseCompletion(
  804. IN PDEVICE_OBJECT DeviceObject,
  805. IN PIRP Irp,
  806. IN PVOID Context
  807. )
  808. {
  809. //
  810. // Irp is always freed by our disable routine to prevent a race
  811. // condition where we don't know if we have called IoCancelIrp
  812. // yet or not.
  813. //
  814. KeSetEvent(CnpIpDisableMediaSenseEvent, IO_NO_INCREMENT, FALSE);
  815. return(STATUS_MORE_PROCESSING_REQUIRED);
  816. } // CnpWmiPnpDisableMediaSenseCompletion
  817. VOID
  818. CnpWmiPnpUpdateCurrentInterface(
  819. IN PCNP_INTERFACE UpdateInterface
  820. )
  821. /*++
  822. Routine Description:
  823. Updates the CurrentInterface for interfaces after the local
  824. interface is connected or disconnected. Called in response
  825. to WMI NDIS media status events.
  826. Arguments:
  827. Interface - A pointer to the interface on which to operate.
  828. Return Value:
  829. None.
  830. Notes:
  831. Called with associated node and network locks held.
  832. Returns with network lock released.
  833. Conforms to calling convention for PCNP_INTERFACE_UPDATE_ROUTINE.
  834. --*/
  835. {
  836. PCNP_NODE node = UpdateInterface->Node;
  837. CnVerifyCpuLockMask(
  838. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  839. 0, // Forbidden
  840. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  841. );
  842. //
  843. // We don't really need the network lock. It's just part of
  844. // the calling convention.
  845. //
  846. CnReleaseLockFromDpc(&(UpdateInterface->Network->Lock));
  847. CnpUpdateNodeCurrentInterface(node);
  848. if ( (node->CurrentInterface == NULL)
  849. ||
  850. ( node->CurrentInterface->State <
  851. ClusnetInterfaceStateOnlinePending
  852. )
  853. )
  854. {
  855. //
  856. // This node is now unreachable.
  857. //
  858. CnpDeclareNodeUnreachable(node);
  859. }
  860. CnVerifyCpuLockMask(
  861. (CNP_NODE_OBJECT_LOCK), // Required
  862. 0, // Forbidden
  863. CNP_NODE_OBJECT_LOCK_MAX // Maximum
  864. );
  865. return;
  866. } // CnpWmiPnpUpdateCurrentInterface
  867. VOID
  868. CnpReconnectLocalInterface(
  869. PCNP_INTERFACE Interface,
  870. PCNP_NETWORK Network
  871. )
  872. /*++
  873. Routine Description:
  874. Changes a local interface from being disconnected to
  875. connected. Called in response to a WMI NDIS media status
  876. connect event or a heartbeat received on a disconnected
  877. interface.
  878. Arguments:
  879. Interface - local interface that is reconnected
  880. Network - network associated with Interface
  881. Return value:
  882. None
  883. Notes:
  884. Called with CnpWmiNdisMediaStatusResource, local node lock,
  885. and Network lock held.
  886. Returns with CnpWmiNdisMediaStatusResource held but neither
  887. lock held.
  888. --*/
  889. {
  890. CnVerifyCpuLockMask(
  891. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  892. 0, // Forbidden
  893. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  894. );
  895. CnTrace(
  896. CXPNP, CnpReconnectLocalInterface,
  897. "[CXPNP] Reconnecting local interface for "
  898. "network ID %u.\n",
  899. Network->Id // LOGULONG
  900. );
  901. //
  902. // Clear the local disconnect flag in the network
  903. // object
  904. //
  905. Network->Flags &= ~CNP_NET_FLAG_LOCALDISCONN;
  906. //
  907. // Reference the network so it can't go away while we
  908. // reprioritize the associated interfaces.
  909. //
  910. CnpReferenceNetwork(Network);
  911. //
  912. // Bring the interface online. This call releases the
  913. // network lock.
  914. //
  915. CnpOnlineInterface(Interface);
  916. //
  917. // Release the node lock before walking the interfaces
  918. // on the network.
  919. //
  920. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  921. //
  922. // Update the CurrentInterface for the other
  923. // nodes in the cluster to reflect the connected
  924. // status of the local interface.
  925. //
  926. CnpWalkInterfacesOnNetwork(
  927. Network,
  928. CnpWmiPnpUpdateCurrentInterface
  929. );
  930. //
  931. // Issue InterfaceUp event to the cluster
  932. // service.
  933. //
  934. CnTrace(
  935. CXPNP, CxWmiNdisReconnectIssueEvent,
  936. "[CXPNP] Issuing InterfaceUp event "
  937. "for node %u on net %u, previous I/F state = %!ifstate!.",
  938. Interface->Node->Id, // LOGULONG
  939. Interface->Network->Id, // LOGULONG
  940. Interface->State // LOGIfState
  941. );
  942. CnIssueEvent(
  943. ClusnetEventNetInterfaceUp,
  944. Interface->Node->Id,
  945. Interface->Network->Id
  946. );
  947. //
  948. // Release the reference on the network object.
  949. //
  950. CnAcquireLock(&(Network->Lock), &(Network->Irql));
  951. CnpDereferenceNetwork(Network);
  952. return;
  953. } // CnpReconnectLocalInterface
  954. VOID
  955. CnpReconnectLocalInterfaceWrapper(
  956. IN PDEVICE_OBJECT DeviceObject,
  957. IN PVOID Context
  958. )
  959. {
  960. PCNP_WMI_RECONNECT_WORKER_CONTEXT context = Context;
  961. PCNP_NETWORK network = NULL;
  962. PCNP_INTERFACE interface = NULL;
  963. CN_IRQL nodeTableIrql;
  964. BOOLEAN acquired = FALSE;
  965. PLIST_ENTRY entry;
  966. CnVerifyCpuLockMask(
  967. 0, // Required
  968. 0xFFFFFFFF, // Forbidden
  969. 0 // Maximum
  970. );
  971. acquired = CnAcquireResourceExclusive(
  972. CnpWmiNdisMediaStatusResource,
  973. TRUE
  974. );
  975. CnAssert(acquired == TRUE);
  976. CnAcquireLock(&CnpNodeTableLock, &nodeTableIrql);
  977. if (CnpLocalNode != NULL) {
  978. CnAcquireLockAtDpc(&(CnpLocalNode->Lock));
  979. CnReleaseLockFromDpc(&CnpNodeTableLock);
  980. CnpLocalNode->Irql = nodeTableIrql;
  981. network = CnpFindNetwork(context->NetworkId);
  982. if (network != NULL) {
  983. //
  984. // Only go through the reconnect if the network
  985. // is currently marked as locally disconnected.
  986. // It is possible that we have already received
  987. // and processed a WMI connect event.
  988. //
  989. if (CnpIsNetworkLocalDisconn(network)) {
  990. for (entry = CnpLocalNode->InterfaceList.Flink;
  991. entry != &(CnpLocalNode->InterfaceList);
  992. entry = entry->Flink
  993. )
  994. {
  995. interface = CONTAINING_RECORD(
  996. entry,
  997. CNP_INTERFACE,
  998. NodeLinkage
  999. );
  1000. if (interface->Network == network) {
  1001. CnpReconnectLocalInterface(
  1002. interface,
  1003. network
  1004. );
  1005. //
  1006. // Both node and network locks
  1007. // were released.
  1008. //
  1009. break;
  1010. } else {
  1011. interface = NULL;
  1012. }
  1013. }
  1014. } else {
  1015. CnTrace(
  1016. CXPNP, CnpReconnectLocalInterfaceWrapperRedundant,
  1017. "[CXPNP] Network ID %u is already connected; "
  1018. "aborting reconnect in wrapper.\n",
  1019. network->Id // LOGULONG
  1020. );
  1021. }
  1022. if (interface == NULL) {
  1023. CnReleaseLock(&(network->Lock), network->Irql);
  1024. }
  1025. }
  1026. if (interface == NULL) {
  1027. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  1028. }
  1029. } else {
  1030. CnReleaseLock(&CnpNodeTableLock, nodeTableIrql);
  1031. }
  1032. //
  1033. // Release resource
  1034. //
  1035. if (acquired) {
  1036. CnReleaseResourceForThread(
  1037. CnpWmiNdisMediaStatusResource,
  1038. (ERESOURCE_THREAD) PsGetCurrentThread()
  1039. );
  1040. }
  1041. //
  1042. // Free the workitem and context
  1043. //
  1044. IoFreeWorkItem(context->WorkItem);
  1045. CnFreePool(context);
  1046. CnVerifyCpuLockMask(
  1047. 0, // Required
  1048. 0xFFFFFFFF, // Forbidden
  1049. 0 // Maximum
  1050. );
  1051. return;
  1052. } // CnpReconnectLocalInterfaceWrapper
  1053. VOID
  1054. CnpDisconnectLocalInterface(
  1055. PCNP_INTERFACE Interface,
  1056. PCNP_NETWORK Network
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. Changes a local interface from being connected to
  1061. disconnected. Called in response to a WMI NDIS media status
  1062. disconnect event or an NDIS query that returns media
  1063. disconnected.
  1064. Arguments:
  1065. Interface - local interface that is reconnected
  1066. Network - network associated with Interface
  1067. Return value:
  1068. None
  1069. Notes:
  1070. Called with CnpWmiNdisMediaStatusResource, local node lock,
  1071. and Network lock held.
  1072. Returns with CnpWmiNdisMediaStatusResource held but neither
  1073. lock held.
  1074. --*/
  1075. {
  1076. CnVerifyCpuLockMask(
  1077. (CNP_NODE_OBJECT_LOCK | CNP_NETWORK_OBJECT_LOCK), // Required
  1078. 0, // Forbidden
  1079. CNP_NETWORK_OBJECT_LOCK_MAX // Maximum
  1080. );
  1081. CnTrace(
  1082. CXPNP, CnpDisconnectLocalInterface,
  1083. "[CXPNP] Interface for network ID %u "
  1084. "disconnected.\n",
  1085. Network->Id // LOGULONG
  1086. );
  1087. //
  1088. // Set the local disconnect flag in the network
  1089. // object
  1090. //
  1091. Network->Flags |= CNP_NET_FLAG_LOCALDISCONN;
  1092. //
  1093. // Reference the network so it can't go away while we
  1094. // reprioritize the associated interfaces.
  1095. //
  1096. CnpReferenceNetwork(Network);
  1097. //
  1098. // Fail the interface. This call releases the
  1099. // network lock.
  1100. //
  1101. CnpFailInterface(Interface);
  1102. //
  1103. // Release the node lock before walking the interfaces
  1104. // on the network.
  1105. //
  1106. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  1107. //
  1108. // Update the CurrentInterface for the other
  1109. // nodes in the cluster to reflect the disconnected
  1110. // status of the local interface.
  1111. //
  1112. CnpWalkInterfacesOnNetwork(
  1113. Network,
  1114. CnpWmiPnpUpdateCurrentInterface
  1115. );
  1116. //
  1117. // Issue InterfaceFailed event to the cluster
  1118. // service.
  1119. //
  1120. CnTrace(
  1121. CXPNP, CnpLocalDisconnectIssueEvent,
  1122. "[CXPNP] Issuing InterfaceFailed event "
  1123. "for node %u on net %u, previous I/F state = %!ifstate!.",
  1124. Interface->Node->Id, // LOGULONG
  1125. Interface->Network->Id, // LOGULONG
  1126. Interface->State // LOGIfState
  1127. );
  1128. CnIssueEvent(
  1129. ClusnetEventNetInterfaceFailed,
  1130. Interface->Node->Id,
  1131. Interface->Network->Id
  1132. );
  1133. //
  1134. // Release the reference on the network object.
  1135. //
  1136. CnAcquireLock(&(Network->Lock), &(Network->Irql));
  1137. CnpDereferenceNetwork(Network);
  1138. return;
  1139. } // CnpDisconnectLocalInterface
  1140. VOID
  1141. CnpWmiNdisMediaStatusConnectCallback(
  1142. IN PVOID Wnode,
  1143. IN PVOID Context
  1144. )
  1145. {
  1146. PWNODE_SINGLE_INSTANCE wnode = (PWNODE_SINGLE_INSTANCE) Wnode;
  1147. PCNP_INTERFACE interface;
  1148. PCNP_NETWORK network;
  1149. PLIST_ENTRY entry;
  1150. CN_IRQL nodeTableIrql;
  1151. BOOLEAN acquired = FALSE;
  1152. CnVerifyCpuLockMask(
  1153. 0, // Required
  1154. 0xFFFFFFFF, // Forbidden
  1155. 0 // Maximum
  1156. );
  1157. IF_CNDBG(CN_DEBUG_CONFIG) {
  1158. CNPRINT((
  1159. "[CX] Received WMI NDIS status media connect event.\n"
  1160. ));
  1161. }
  1162. //
  1163. // Serialize events as much as possible, since clusnet spinlocks
  1164. // may be acquired and released repeatedly.
  1165. //
  1166. // Note that there may not be any guarantees that WMI event
  1167. // ordering is guaranteed. The fallback mechanism for clusnet
  1168. // is heartbeats -- if a heartbeat is received on an interface,
  1169. // we know the interface is connected.
  1170. //
  1171. acquired = CnAcquireResourceExclusive(
  1172. CnpWmiNdisMediaStatusResource,
  1173. TRUE
  1174. );
  1175. CnAssert(acquired == TRUE);
  1176. //
  1177. // Figure out if this callback is for one of this node's
  1178. // registered interfaces by comparing the WMI provider ID
  1179. // in the WNODE header to the WMI provider IDs of this
  1180. // node's adapters.
  1181. //
  1182. CnAcquireLock(&CnpNodeTableLock, &nodeTableIrql);
  1183. if (CnpLocalNode != NULL) {
  1184. CnAcquireLockAtDpc(&(CnpLocalNode->Lock));
  1185. CnReleaseLockFromDpc(&CnpNodeTableLock);
  1186. CnpLocalNode->Irql = nodeTableIrql;
  1187. network = NULL;
  1188. for (entry = CnpLocalNode->InterfaceList.Flink;
  1189. entry != &(CnpLocalNode->InterfaceList);
  1190. entry = entry->Flink
  1191. )
  1192. {
  1193. interface = CONTAINING_RECORD(
  1194. entry,
  1195. CNP_INTERFACE,
  1196. NodeLinkage
  1197. );
  1198. if (wnode->WnodeHeader.ProviderId
  1199. == interface->AdapterWMIProviderId) {
  1200. //
  1201. // Found the local interface corresponding to this
  1202. // address.
  1203. //
  1204. network = interface->Network;
  1205. //
  1206. // Start by checking if we believe the network is
  1207. // currently disconnected.
  1208. //
  1209. CnAcquireLockAtDpc(&(network->Lock));
  1210. network->Irql = DISPATCH_LEVEL;
  1211. if (CnpIsNetworkLocalDisconn(network)) {
  1212. CnTrace(
  1213. CXPNP, CxWmiNdisConnectNet,
  1214. "[CXPNP] Interface for network ID %u "
  1215. "connected.\n",
  1216. network->Id // LOGULONG
  1217. );
  1218. CnpReconnectLocalInterface(interface, network);
  1219. //
  1220. // Node and network locks were released
  1221. //
  1222. } else {
  1223. CnTrace(
  1224. CXPNP, CxWmiNdisConnectNetRedundant,
  1225. "[CXPNP] Ignoring redundant WMI NDIS connect "
  1226. "event for interface for network ID %u.\n",
  1227. network->Id // LOGULONG
  1228. );
  1229. CnReleaseLockFromDpc(&(network->Lock));
  1230. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  1231. }
  1232. break;
  1233. }
  1234. }
  1235. if (network == NULL) {
  1236. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  1237. }
  1238. }
  1239. else {
  1240. CnReleaseLock(&CnpNodeTableLock, nodeTableIrql);
  1241. }
  1242. IF_CNDBG(CN_DEBUG_CONFIG) {
  1243. if (network != NULL) {
  1244. CNPRINT((
  1245. "[CX] Interface for network ID %u connected.\n",
  1246. network->Id
  1247. ));
  1248. } else {
  1249. CNPRINT((
  1250. "[CX] Unknown interface connected, provider id %lx\n",
  1251. wnode->WnodeHeader.ProviderId
  1252. ));
  1253. }
  1254. }
  1255. //
  1256. // Release resource
  1257. //
  1258. if (acquired) {
  1259. CnReleaseResourceForThread(
  1260. CnpWmiNdisMediaStatusResource,
  1261. (ERESOURCE_THREAD) PsGetCurrentThread()
  1262. );
  1263. }
  1264. CnVerifyCpuLockMask(
  1265. 0, // Required
  1266. 0xFFFFFFFF, // Forbidden
  1267. 0 // Maximum
  1268. );
  1269. return;
  1270. } // CnpWmiNdisMediaStatusConnectCallback
  1271. VOID
  1272. CnpWmiNdisMediaStatusDisconnectCallback(
  1273. IN PVOID Wnode,
  1274. IN PVOID Context
  1275. )
  1276. {
  1277. PWNODE_SINGLE_INSTANCE wnode = (PWNODE_SINGLE_INSTANCE) Wnode;
  1278. PCNP_INTERFACE interface;
  1279. PCNP_NETWORK network;
  1280. PLIST_ENTRY entry;
  1281. CN_IRQL nodeTableIrql;
  1282. BOOLEAN acquired = FALSE;
  1283. CnVerifyCpuLockMask(
  1284. 0, // Required
  1285. 0xFFFFFFFF, // Forbidden
  1286. 0 // Maximum
  1287. );
  1288. IF_CNDBG(CN_DEBUG_CONFIG) {
  1289. CNPRINT((
  1290. "[CX] Received WMI NDIS status media disconnect event.\n"
  1291. ));
  1292. }
  1293. CnTrace(CXPNP, CxWmiNdisDisconnect,
  1294. "[CXPNP] Received WMI NDIS status media disconnect event.\n"
  1295. );
  1296. //
  1297. // Serialize events as much as possible, since clusnet spinlocks
  1298. // may be acquired and released repeatedly.
  1299. //
  1300. // Note that there may not be any guarantees that WMI event
  1301. // ordering is guaranteed. The fallback mechanism for clusnet
  1302. // is heartbeats -- if a heartbeat is received on an interface,
  1303. // we know the interface is connected.
  1304. //
  1305. acquired = CnAcquireResourceExclusive(
  1306. CnpWmiNdisMediaStatusResource,
  1307. TRUE
  1308. );
  1309. CnAssert(acquired == TRUE);
  1310. //
  1311. // Figure out if this callback is for one of this node's
  1312. // registered interfaces by comparing the WMI provider ID
  1313. // in the WNODE header to the WMI provider IDs of this
  1314. // node's adapters.
  1315. //
  1316. CnAcquireLock(&CnpNodeTableLock, &nodeTableIrql);
  1317. if (CnpLocalNode != NULL) {
  1318. CnAcquireLockAtDpc(&(CnpLocalNode->Lock));
  1319. CnReleaseLockFromDpc(&CnpNodeTableLock);
  1320. CnpLocalNode->Irql = nodeTableIrql;
  1321. network = NULL;
  1322. for (entry = CnpLocalNode->InterfaceList.Flink;
  1323. entry != &(CnpLocalNode->InterfaceList);
  1324. entry = entry->Flink
  1325. )
  1326. {
  1327. interface = CONTAINING_RECORD(
  1328. entry,
  1329. CNP_INTERFACE,
  1330. NodeLinkage
  1331. );
  1332. if (wnode->WnodeHeader.ProviderId
  1333. == interface->AdapterWMIProviderId) {
  1334. //
  1335. // Found the local interface object corresponding
  1336. // to this adapter.
  1337. //
  1338. network = interface->Network;
  1339. CnAcquireLockAtDpc(&(network->Lock));
  1340. network->Irql = DISPATCH_LEVEL;
  1341. CnpDisconnectLocalInterface(interface, network);
  1342. break;
  1343. }
  1344. }
  1345. if (network == NULL) {
  1346. CnReleaseLock(&(CnpLocalNode->Lock), CnpLocalNode->Irql);
  1347. }
  1348. }
  1349. else {
  1350. CnReleaseLock(&CnpNodeTableLock, nodeTableIrql);
  1351. }
  1352. IF_CNDBG(CN_DEBUG_CONFIG) {
  1353. if (network != NULL) {
  1354. CNPRINT((
  1355. "[CX] Interface for network ID %u disconnected.\n",
  1356. network->Id
  1357. ));
  1358. } else {
  1359. CNPRINT((
  1360. "[CX] Unknown interface disconnected, provider id %lx\n",
  1361. wnode->WnodeHeader.ProviderId
  1362. ));
  1363. }
  1364. }
  1365. //
  1366. // Release resource
  1367. //
  1368. if (acquired) {
  1369. CnReleaseResourceForThread(
  1370. CnpWmiNdisMediaStatusResource,
  1371. (ERESOURCE_THREAD) PsGetCurrentThread()
  1372. );
  1373. }
  1374. CnVerifyCpuLockMask(
  1375. 0, // Required
  1376. 0xFFFFFFFF, // Forbidden
  1377. 0 // Maximum
  1378. );
  1379. return;
  1380. } // CnpWmiNdisMediaStatusDisconnectCallback