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.

355 lines
10 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: fni.cpp
  4. //
  5. // Description:
  6. //
  7. // Filter Node Instance
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // Mike McLaughlin
  12. //
  13. // History: Date Author Comment
  14. //
  15. // To Do: Date Author Comment
  16. //
  17. //@@END_MSINTERNAL
  18. //
  19. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  20. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  22. // PURPOSE.
  23. //
  24. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. #include "common.h"
  28. //---------------------------------------------------------------------------
  29. //---------------------------------------------------------------------------
  30. CFilterNodeInstance::~CFilterNodeInstance(
  31. )
  32. {
  33. Assert(this);
  34. DPF1(95, "~CFilterNodeInstance: %08x", this);
  35. RemoveListCheck();
  36. UnregisterTargetDeviceChangeNotification();
  37. //
  38. // if hFilter == NULL && pFileObject != NULL
  39. // it means that this filter instance is for a GFX
  40. // do not try to dereference the file object in that case
  41. //
  42. if( (hFilter != NULL) && (pFileObject != NULL) ) {
  43. AssertFileObject(pFileObject);
  44. ObDereferenceObject(pFileObject);
  45. }
  46. if(hFilter != NULL) {
  47. AssertStatus(ZwClose(hFilter));
  48. }
  49. }
  50. NTSTATUS
  51. CFilterNodeInstance::Create(
  52. PFILTER_NODE_INSTANCE *ppFilterNodeInstance,
  53. PLOGICAL_FILTER_NODE pLogicalFilterNode,
  54. PDEVICE_NODE pDeviceNode,
  55. BOOL fReuseInstance
  56. )
  57. {
  58. PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
  59. PLOGICAL_FILTER_NODE pLogicalFilterNode2;
  60. NTSTATUS Status = STATUS_SUCCESS;
  61. Assert(pLogicalFilterNode);
  62. Assert(pLogicalFilterNode->pFilterNode);
  63. //
  64. // AEC is a special filter we need both of the logical filters.
  65. // So AddRef for all FilterNodeInstances of all aec logical filters.
  66. //
  67. if(pLogicalFilterNode->GetType() & FILTER_TYPE_AEC) {
  68. FOR_EACH_LIST_ITEM(
  69. &pLogicalFilterNode->pFilterNode->lstLogicalFilterNode,
  70. pLogicalFilterNode2) {
  71. FOR_EACH_LIST_ITEM(
  72. &pLogicalFilterNode2->lstFilterNodeInstance,
  73. pFilterNodeInstance) {
  74. pFilterNodeInstance->AddRef();
  75. ASSERT(NT_SUCCESS(Status));
  76. goto exit;
  77. } END_EACH_LIST_ITEM
  78. } END_EACH_LIST_ITEM
  79. }
  80. else {
  81. //
  82. // For reusable filters find the appropriate FilterNodeInstances and
  83. // AddRef.
  84. //
  85. if(fReuseInstance) {
  86. FOR_EACH_LIST_ITEM(
  87. &pLogicalFilterNode->lstFilterNodeInstance,
  88. pFilterNodeInstance) {
  89. if(pDeviceNode == NULL ||
  90. pDeviceNode == pFilterNodeInstance->pDeviceNode) {
  91. pFilterNodeInstance->AddRef();
  92. ASSERT(NT_SUCCESS(Status));
  93. goto exit;
  94. }
  95. } END_EACH_LIST_ITEM
  96. }
  97. }
  98. //
  99. // Otherwise create a FilterNodeInstance.
  100. //
  101. Status = Create(&pFilterNodeInstance, pLogicalFilterNode->pFilterNode);
  102. if(!NT_SUCCESS(Status)) {
  103. goto exit;
  104. }
  105. pFilterNodeInstance->pDeviceNode = pDeviceNode;
  106. pFilterNodeInstance->AddList(&pLogicalFilterNode->lstFilterNodeInstance);
  107. exit:
  108. *ppFilterNodeInstance = pFilterNodeInstance;
  109. return(Status);
  110. }
  111. NTSTATUS
  112. CFilterNodeInstance::Create(
  113. PFILTER_NODE_INSTANCE *ppFilterNodeInstance,
  114. PFILTER_NODE pFilterNode
  115. )
  116. {
  117. PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
  118. NTSTATUS Status = STATUS_SUCCESS;
  119. Assert(pFilterNode);
  120. pFilterNodeInstance = new FILTER_NODE_INSTANCE;
  121. if(pFilterNodeInstance == NULL) {
  122. Status = STATUS_INSUFFICIENT_RESOURCES;
  123. goto exit;
  124. }
  125. pFilterNodeInstance->pFilterNode = pFilterNode;
  126. pFilterNodeInstance->AddRef();
  127. if(pFilterNode->GetType() & FILTER_TYPE_GFX) {
  128. //
  129. // if it is a GFX do not try to open the device, just re-use
  130. // the file object which we cached during AddGfx
  131. //
  132. pFilterNodeInstance->pFileObject = pFilterNode->GetFileObject();
  133. pFilterNodeInstance->hFilter = NULL;
  134. Status = STATUS_SUCCESS;
  135. }
  136. else {
  137. //
  138. // if it is not a GFX go ahead and open the device.
  139. //
  140. Status = pFilterNode->OpenDevice(&pFilterNodeInstance->hFilter);
  141. }
  142. if(!NT_SUCCESS(Status)) {
  143. DPF2(10, "CFilterNodeInstance::Create OpenDevice Failed: %08x FN: %08x",
  144. Status,
  145. pFilterNode);
  146. pFilterNodeInstance->hFilter = NULL;
  147. goto exit;
  148. }
  149. if (pFilterNodeInstance->hFilter) {
  150. Status = ObReferenceObjectByHandle(
  151. pFilterNodeInstance->hFilter,
  152. GENERIC_READ | GENERIC_WRITE,
  153. NULL,
  154. KernelMode,
  155. (PVOID*)&pFilterNodeInstance->pFileObject,
  156. NULL);
  157. }
  158. if(!NT_SUCCESS(Status)) {
  159. Trap();
  160. pFilterNodeInstance->pFileObject = NULL;
  161. goto exit;
  162. }
  163. AssertFileObject(pFilterNodeInstance->pFileObject);
  164. Status = pFilterNodeInstance->RegisterTargetDeviceChangeNotification();
  165. if(!NT_SUCCESS(Status)) {
  166. goto exit;
  167. }
  168. DPF2(95, "CFilterNodeInstance::Create %08x FN: %08x",
  169. pFilterNodeInstance,
  170. pFilterNode);
  171. exit:
  172. if(!NT_SUCCESS(Status)) {
  173. if (pFilterNodeInstance) {
  174. pFilterNodeInstance->Destroy();
  175. }
  176. pFilterNodeInstance = NULL;
  177. }
  178. *ppFilterNodeInstance = pFilterNodeInstance;
  179. return(Status);
  180. }
  181. //---------------------------------------------------------------------------
  182. NTSTATUS
  183. CFilterNodeInstance::RegisterTargetDeviceChangeNotification(
  184. )
  185. {
  186. NTSTATUS Status;
  187. ASSERT(gpDeviceInstance != NULL);
  188. ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
  189. ASSERT(pNotificationHandle == NULL);
  190. Status = IoRegisterPlugPlayNotification(
  191. EventCategoryTargetDeviceChange,
  192. 0,
  193. pFileObject,
  194. gpDeviceInstance->pPhysicalDeviceObject->DriverObject,
  195. (NTSTATUS (*)(PVOID, PVOID))
  196. CFilterNodeInstance::TargetDeviceChangeNotification,
  197. this,
  198. &pNotificationHandle);
  199. //
  200. // ISSUE: 02/20/02 ALPERS
  201. // Can this IoRegisterPlugPlayNotification ever return
  202. // STATUS_NOT_IMPLEMENTED on XP?
  203. // This code does not make sense to me...
  204. //
  205. if(!NT_SUCCESS(Status)) {
  206. if(Status != STATUS_NOT_IMPLEMENTED) {
  207. goto exit;
  208. }
  209. // ISSUE: 02/20/02 ALPERS
  210. // According to Adrian Oney...
  211. // On Win2K/XP, when a driver passes in a handle
  212. // (EventCategoryTargetDeviceChange), PnP tries to find the hardware
  213. // backing that handle. It does this by sending a "homing beacon" IRP,
  214. // IRP_MN_QUERY_DEVICE_RELATIONS(TargetDeviceRelation). Filesystems
  215. // and legacy side-stacks typically forward this to the underlying
  216. // WDM stack. The PDO responds by identifying itself as the underlying
  217. // hardware. If a filesystem or legacy-stack fails this request
  218. // (or a broken WDM stack fails the request), then
  219. // STATUS_NOT_IMPLEMENTED would be returned.
  220. //
  221. // Therefore this ASSERT is inserted to see if we ever get
  222. // STATUS_NOT_IMPLEMENTED.
  223. //
  224. ASSERT(0);
  225. Status = STATUS_SUCCESS;
  226. }
  227. DPF2(100, "RegisterTargetDeviceChangeNotification: FNI: %08x PFO: %08x",
  228. this,
  229. this->pFileObject);
  230. exit:
  231. return(Status);
  232. }
  233. VOID
  234. CFilterNodeInstance::UnregisterTargetDeviceChangeNotification(
  235. )
  236. {
  237. HANDLE hNotification;
  238. DPF1(100, "UnregisterTargetDeviceChangeNotification: FNI: %08x", this);
  239. hNotification = pNotificationHandle;
  240. if(hNotification != NULL) {
  241. pNotificationHandle = NULL;
  242. IoUnregisterPlugPlayNotification(hNotification);
  243. }
  244. }
  245. NTSTATUS
  246. CFilterNodeInstance::DeviceQueryRemove(
  247. )
  248. {
  249. PGRAPH_NODE_INSTANCE pGraphNodeInstance;
  250. PDEVICE_NODE pDeviceNode;
  251. PGRAPH_NODE pGraphNode;
  252. FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
  253. FOR_EACH_LIST_ITEM(&pDeviceNode->lstGraphNode, pGraphNode) {
  254. FOR_EACH_LIST_ITEM(
  255. &pGraphNode->lstGraphNodeInstance,
  256. pGraphNodeInstance) {
  257. for(ULONG n = 0;
  258. n < pGraphNodeInstance->Topology.TopologyNodesCount;
  259. n++) {
  260. pGraphNodeInstance->
  261. papFilterNodeInstanceTopologyTable[n]->Destroy();
  262. pGraphNodeInstance->
  263. papFilterNodeInstanceTopologyTable[n] = NULL;
  264. }
  265. } END_EACH_LIST_ITEM
  266. } END_EACH_LIST_ITEM
  267. } END_EACH_LIST_ITEM
  268. return(STATUS_SUCCESS);
  269. }
  270. NTSTATUS
  271. CFilterNodeInstance::TargetDeviceChangeNotification(
  272. IN PTARGET_DEVICE_REMOVAL_NOTIFICATION pNotification,
  273. IN PFILTER_NODE_INSTANCE pFilterNodeInstance
  274. )
  275. {
  276. DPF3(5, "TargetDeviceChangeNotification: FNI: %08x PFO: %08x %s",
  277. pFilterNodeInstance,
  278. pNotification->FileObject,
  279. DbgGuid2Sz(&pNotification->Event));
  280. if(IsEqualGUID(
  281. &pNotification->Event,
  282. &GUID_TARGET_DEVICE_REMOVE_COMPLETE) ||
  283. IsEqualGUID(
  284. &pNotification->Event,
  285. &GUID_TARGET_DEVICE_QUERY_REMOVE)) {
  286. NTSTATUS Status = STATUS_SUCCESS;
  287. LARGE_INTEGER li = {0, 10000}; // wait for 1 ms
  288. //
  289. // ISSUE: 02/20/02 ALPERS
  290. // It is not clear to me yet what happens if the mutex times out.
  291. // We will return STATUS_TIMEOUT, then what.
  292. // Should we veto the removal if we cannot acquire the mutex?s
  293. //
  294. Status = KeWaitForMutexObject(
  295. &gMutex,
  296. Executive,
  297. KernelMode,
  298. FALSE,
  299. &li);
  300. if(Status != STATUS_TIMEOUT) {
  301. DeviceQueryRemove();
  302. ReleaseMutex();
  303. }
  304. else {
  305. DPF1(5, "TargetDeviceChangeNotification: FAILED %08x", Status);
  306. }
  307. }
  308. return(STATUS_SUCCESS);
  309. }
  310. //---------------------------------------------------------------------------