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.

2188 lines
56 KiB

  1. #include "gpcpre.h"
  2. /*++
  3. Copyright (c) 1996 Microsoft Corporation
  4. Module Name:
  5. ioctl.c
  6. Abstract:
  7. Creates symbolic link to receive ioctls from user mode and contains the
  8. ioctl case statement.
  9. Author:
  10. Yoram Bernet (yoramb) May, 7th. 1997
  11. Environment:
  12. Kernel Mode
  13. Revision History:
  14. Ofer Bar (oferbar) Oct 1, 1997 - revision II
  15. --*/
  16. #pragma hdrstop
  17. VOID
  18. IoctlCleanup(
  19. ULONG ShutdownMask
  20. );
  21. NTSTATUS
  22. GPCIoctl(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp
  25. );
  26. VOID
  27. CancelPendingIrpCfInfo(
  28. IN PDEVICE_OBJECT Device,
  29. IN PIRP Irp
  30. );
  31. VOID
  32. CancelPendingIrpNotify(
  33. IN PDEVICE_OBJECT Device,
  34. IN PIRP Irp
  35. );
  36. NTSTATUS
  37. ProxyGpcRegisterClient(
  38. PVOID ioBuffer,
  39. ULONG inputBufferLength,
  40. ULONG *outputBufferLength,
  41. PFILE_OBJECT FileObject
  42. );
  43. NTSTATUS
  44. ProxyGpcDeregisterClient(
  45. PVOID ioBuffer,
  46. ULONG inputBufferLength,
  47. ULONG *outputBufferLength
  48. );
  49. NTSTATUS
  50. ProxyGpcAddCfInfo(
  51. PVOID ioBuffer,
  52. ULONG inputBufferLength,
  53. ULONG *outputBufferLength,
  54. PIRP Irp
  55. );
  56. NTSTATUS
  57. ProxyGpcModifyCfInfo(
  58. PVOID ioBuffer,
  59. ULONG inputBufferLength,
  60. ULONG *outputBufferLength,
  61. PIRP Irp
  62. );
  63. NTSTATUS
  64. ProxyGpcRemoveCfInfo(
  65. PVOID ioBuffer,
  66. ULONG inputBufferLength,
  67. ULONG *outputBufferLength,
  68. PIRP Irp
  69. );
  70. NTSTATUS
  71. ProxyGpcAddPattern(
  72. PVOID ioBuffer,
  73. ULONG inputBufferLength,
  74. ULONG *outputBufferLength
  75. );
  76. NTSTATUS
  77. ProxyGpcRemovePattern(
  78. PVOID ioBuffer,
  79. ULONG inputBufferLength,
  80. ULONG *outputBufferLength
  81. );
  82. NTSTATUS
  83. ProxyGpcEnumCfInfo(
  84. PVOID ioBuffer,
  85. ULONG inputBufferLength,
  86. ULONG *outputBufferLength
  87. );
  88. GPC_CLIENT_FUNC_LIST CallBackProxyList;
  89. PDEVICE_OBJECT GPCDeviceObject;
  90. LIST_ENTRY PendingIrpCfInfoList;
  91. LIST_ENTRY PendingIrpNotifyList;
  92. LIST_ENTRY QueuedNotificationList;
  93. LIST_ENTRY QueuedCompletionList;
  94. /* End Forward */
  95. #pragma NDIS_PAGEABLE_FUNCTION(GPCIoctl)
  96. UNICODE_STRING GpcDriverName = {sizeof(DD_GPC_DEVICE_NAME)-2,
  97. sizeof(DD_GPC_DEVICE_NAME),
  98. DD_GPC_DEVICE_NAME};
  99. NTSTATUS
  100. IoctlInitialize(
  101. PDRIVER_OBJECT DriverObject,
  102. PULONG InitShutdownMask
  103. )
  104. /*++
  105. Routine Description:
  106. Perform initialization
  107. Arguments:
  108. DriverObject - pointer to DriverObject from DriverEntry
  109. InitShutdownMask - pointer to mask used to indicate which events have been
  110. successfully init'ed
  111. Return Value:
  112. STATUS_SUCCESS if everything worked ok
  113. --*/
  114. {
  115. NTSTATUS Status;
  116. UINT FuncIndex;
  117. InitializeListHead(&PendingIrpCfInfoList);
  118. InitializeListHead(&PendingIrpNotifyList);
  119. InitializeListHead(&QueuedNotificationList);
  120. InitializeListHead(&QueuedCompletionList);
  121. //
  122. // Initialize the driver object's entry points
  123. //
  124. DriverObject->FastIoDispatch = NULL;
  125. for (FuncIndex = 0; FuncIndex <= IRP_MJ_MAXIMUM_FUNCTION; FuncIndex++) {
  126. DriverObject->MajorFunction[FuncIndex] = GPCIoctl;
  127. }
  128. Status = IoCreateDevice(DriverObject,
  129. 0,
  130. &GpcDriverName,
  131. FILE_DEVICE_NETWORK,
  132. FILE_DEVICE_SECURE_OPEN,
  133. FALSE,
  134. &GPCDeviceObject);
  135. if ( NT_SUCCESS( Status )) {
  136. *InitShutdownMask |= SHUTDOWN_DELETE_DEVICE;
  137. GPCDeviceObject->Flags |= DO_BUFFERED_IO;
  138. /* yoramb - don't need a symbolic link for now...
  139. Status = IoCreateSymbolicLink( &GPCSymbolicName, &GPCDriverName );
  140. if ( NT_SUCCESS( Status )) {
  141. *InitShutdownMask |= SHUTDOWN_DELETE_SYMLINK;
  142. } else {
  143. DBGPRINT(IOCTL, ("IoCreateSymbolicLink Failed (%08X): %ls -> %ls\n",
  144. Status, GPCSymbolicName.Buffer, PSDriverName.Buffer));
  145. }
  146. */
  147. } else {
  148. DbgPrint("IoCreateDevice failed. Status = %x\n", Status);
  149. GPCDeviceObject = NULL;
  150. }
  151. //
  152. // Initialize the callback functions. These are called by the
  153. // kernel Gpc and turned into async notifications to the user.
  154. // For now, the user does not get callbacks, so they are NULL.
  155. //
  156. CallBackProxyList.GpcVersion = GpcMajorVersion;
  157. CallBackProxyList.ClAddCfInfoCompleteHandler = NULL;
  158. CallBackProxyList.ClAddCfInfoNotifyHandler = NULL;
  159. CallBackProxyList.ClModifyCfInfoCompleteHandler = NULL;
  160. CallBackProxyList.ClModifyCfInfoNotifyHandler = NULL;
  161. CallBackProxyList.ClRemoveCfInfoCompleteHandler = NULL;
  162. CallBackProxyList.ClRemoveCfInfoNotifyHandler = NULL;
  163. return Status;
  164. }
  165. NTSTATUS
  166. GPCIoctl(
  167. IN PDEVICE_OBJECT DeviceObject,
  168. IN PIRP Irp
  169. )
  170. /*++
  171. Routine Description:
  172. Process the IRPs sent to this device.
  173. Arguments:
  174. DeviceObject - pointer to a device object
  175. Irp - pointer to an I/O Request Packet
  176. Return Value:
  177. None
  178. --*/
  179. {
  180. PIO_STACK_LOCATION irpStack;
  181. PVOID ioBuffer;
  182. ULONG inputBufferLength;
  183. ULONG outputBufferLength;
  184. ULONG ioControlCode;
  185. UCHAR saveControlFlags;
  186. NTSTATUS Status = STATUS_SUCCESS;
  187. #if DBG
  188. KIRQL irql = KeGetCurrentIrql();
  189. KIRQL irql2;
  190. HANDLE thrd = PsGetCurrentThreadId();
  191. #endif
  192. PAGED_CODE();
  193. //
  194. // Init to default settings- we only expect 1 type of
  195. // IOCTL to roll through here, all others an error.
  196. //
  197. Irp->IoStatus.Status = STATUS_SUCCESS;
  198. Irp->IoStatus.Information = 0;
  199. //
  200. // Get a pointer to the current location in the Irp. This is where
  201. // the function codes and parameters are located.
  202. //
  203. irpStack = IoGetCurrentIrpStackLocation(Irp);
  204. //
  205. // Get the pointer to the input/output buffer and it's length
  206. //
  207. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  208. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  209. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  210. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  211. saveControlFlags = irpStack->Control;
  212. TRACE(LOCKS, thrd, irql, "GPCIoctl");
  213. switch (irpStack->MajorFunction) {
  214. case IRP_MJ_CREATE:
  215. DBGPRINT(IOCTL, ("IRP Create\n"));
  216. break;
  217. case IRP_MJ_READ:
  218. DBGPRINT(IOCTL, ("IRP Read\n"));
  219. break;
  220. case IRP_MJ_CLOSE:
  221. DBGPRINT(IOCTL, ("IRP Close\n"));
  222. TRACE(IOCTL, irpStack->FileObject, 0, "IRP Close");
  223. //
  224. // make sure we clean all the objects for this particular
  225. // file object, since it's closing right now.
  226. //
  227. CloseAllObjects(irpStack->FileObject, Irp);
  228. break;
  229. case IRP_MJ_CLEANUP:
  230. DBGPRINT(IOCTL, ("IRP Cleanup\n"));
  231. break;
  232. case IRP_MJ_SHUTDOWN:
  233. DBGPRINT(IOCTL, ("IRP Shutdown\n"));
  234. break;
  235. case IRP_MJ_DEVICE_CONTROL:
  236. DBGPRINT(IOCTL, ("GPCIoctl: ioctl=0x%X, IRP=0x%X\n",
  237. ioControlCode, (ULONG_PTR)Irp));
  238. TRACE(IOCTL, ioControlCode, Irp, "GPCIoctl.irp:");
  239. //
  240. // Mark the IRP as Pending BEFORE calling any dispatch routine.
  241. // If Status is actually set to STATUS_PENDING, we assume the IRP
  242. // is ready to be returned.
  243. // It is possible the IoCompleteRequest has been called async for the
  244. // IRP, but this should be taken care of by the IO subsystem.
  245. //
  246. IoMarkIrpPending(Irp);
  247. switch (ioControlCode) {
  248. case IOCTL_GPC_REGISTER_CLIENT:
  249. Status = ProxyGpcRegisterClient(ioBuffer,
  250. inputBufferLength,
  251. &outputBufferLength,
  252. irpStack->FileObject);
  253. break;
  254. case IOCTL_GPC_DEREGISTER_CLIENT:
  255. Status = ProxyGpcDeregisterClient(ioBuffer,
  256. inputBufferLength,
  257. &outputBufferLength);
  258. break;
  259. case IOCTL_GPC_ADD_CF_INFO:
  260. Status = ProxyGpcAddCfInfo(ioBuffer,
  261. inputBufferLength,
  262. &outputBufferLength,
  263. Irp
  264. );
  265. break;
  266. case IOCTL_GPC_MODIFY_CF_INFO:
  267. Status = ProxyGpcModifyCfInfo(ioBuffer,
  268. inputBufferLength,
  269. &outputBufferLength,
  270. Irp
  271. );
  272. break;
  273. case IOCTL_GPC_REMOVE_CF_INFO:
  274. Status = ProxyGpcRemoveCfInfo(ioBuffer,
  275. inputBufferLength,
  276. &outputBufferLength,
  277. Irp
  278. );
  279. break;
  280. case IOCTL_GPC_ADD_PATTERN:
  281. Status = ProxyGpcAddPattern(ioBuffer,
  282. inputBufferLength,
  283. &outputBufferLength);
  284. break;
  285. case IOCTL_GPC_REMOVE_PATTERN:
  286. Status = ProxyGpcRemovePattern(ioBuffer,
  287. inputBufferLength,
  288. &outputBufferLength);
  289. break;
  290. case IOCTL_GPC_ENUM_CFINFO:
  291. Status = ProxyGpcEnumCfInfo(ioBuffer,
  292. inputBufferLength,
  293. &outputBufferLength);
  294. break;
  295. case IOCTL_GPC_NOTIFY_REQUEST:
  296. //
  297. // request to pend an IRP
  298. //
  299. Status = CheckQueuedNotification(Irp, &outputBufferLength);
  300. break;
  301. case IOCTL_GPC_GET_ENTRIES:
  302. #ifdef STANDALONE_DRIVER
  303. //
  304. // Return the exported calls in the buffer
  305. //
  306. if (outputBufferLength >= sizeof(glGpcExportedCalls)) {
  307. NdisMoveMemory(ioBuffer,
  308. &glGpcExportedCalls,
  309. sizeof(glGpcExportedCalls));
  310. outputBufferLength = sizeof(glGpcExportedCalls);
  311. } else {
  312. outputBufferLength = sizeof(glGpcExportedCalls);
  313. Status = GPC_STATUS_INSUFFICIENT_BUFFER;
  314. }
  315. #else
  316. Status = STATUS_INVALID_PARAMETER;
  317. #endif
  318. break;
  319. default:
  320. DBGPRINT(IOCTL, ("GPCIoctl: Unknown IRP_MJ_DEVICE_CONTROL\n = %X\n",
  321. ioControlCode));
  322. Status = STATUS_INVALID_PARAMETER;
  323. break;
  324. } // switch (ioControlCode)
  325. break;
  326. default:
  327. DBGPRINT(IOCTL, ("GPCIoctl: Unknown IRP major function = %08X\n",
  328. irpStack->MajorFunction));
  329. Status = STATUS_UNSUCCESSFUL;
  330. break;
  331. }
  332. DBGPRINT(IOCTL, ("GPCIoctl: Status=0x%X, IRP=0x%X, outSize=%d\n",
  333. Status, (ULONG_PTR)Irp, outputBufferLength));
  334. TRACE(IOCTL, Irp, Status, "GPCIoctl.Complete:");
  335. if (Status != STATUS_PENDING) {
  336. //
  337. // IRP completed and it's not Pending, we need to restore the Control flags,
  338. // since it might have been marked as Pending before...
  339. //
  340. irpStack->Control = saveControlFlags;
  341. Irp->IoStatus.Status = Status;
  342. Irp->IoStatus.Information = outputBufferLength;
  343. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  344. }
  345. #if DBG
  346. irql2 = KeGetCurrentIrql();
  347. ASSERT(irql == irql2);
  348. #endif
  349. TRACE(LOCKS, thrd, irql2, "GPCIoctl (end)");
  350. return Status;
  351. } // GPCIoctl
  352. VOID
  353. IoctlCleanup(
  354. ULONG ShutdownMask
  355. )
  356. /*++
  357. Routine Description:
  358. Cleanup code for Initialize
  359. Arguments:
  360. ShutdownMask - mask indicating which functions need to be cleaned up
  361. Return Value:
  362. None
  363. --*/
  364. {
  365. /*
  366. if ( ShutdownMask & SHUTDOWN_DELETE_SYMLINK ) {
  367. IoDeleteSymbolicLink( &PSSymbolicName );
  368. }
  369. */
  370. if ( ShutdownMask & SHUTDOWN_DELETE_DEVICE ) {
  371. IoDeleteDevice( GPCDeviceObject );
  372. }
  373. }
  374. NTSTATUS
  375. ProxyGpcRegisterClient(
  376. PVOID ioBuffer,
  377. ULONG inputBufferLength,
  378. ULONG *outputBufferLength,
  379. PFILE_OBJECT FileObject
  380. )
  381. {
  382. NTSTATUS Status;
  383. PCLIENT_BLOCK pClient;
  384. PGPC_REGISTER_CLIENT_REQ GpcReq;
  385. PGPC_REGISTER_CLIENT_RES GpcRes;
  386. if (inputBufferLength < sizeof(GPC_REGISTER_CLIENT_REQ)
  387. ||
  388. *outputBufferLength < sizeof(GPC_REGISTER_CLIENT_RES)
  389. ) {
  390. return STATUS_BUFFER_TOO_SMALL;
  391. }
  392. GpcReq = (PGPC_REGISTER_CLIENT_REQ)ioBuffer;
  393. GpcRes = (PGPC_REGISTER_CLIENT_RES)ioBuffer;
  394. Status = GpcRegisterClient(GpcReq->CfId,
  395. GpcReq->Flags | GPC_FLAGS_USERMODE_CLIENT,
  396. GpcReq->MaxPriorities,
  397. &CallBackProxyList,
  398. GpcReq->ClientContext,
  399. (PGPC_HANDLE)&pClient);
  400. ASSERT(Status != GPC_STATUS_PENDING);
  401. if (Status == STATUS_SUCCESS) {
  402. ASSERT(pClient);
  403. pClient->pFileObject = FileObject;
  404. GpcRes->ClientHandle = AllocateHandle(&pClient->ClHandle, (PVOID)pClient);
  405. }
  406. GpcRes->Status = Status;
  407. *outputBufferLength = sizeof(GPC_REGISTER_CLIENT_RES);
  408. return STATUS_SUCCESS;
  409. }
  410. NTSTATUS
  411. ProxyGpcDeregisterClient(
  412. PVOID ioBuffer,
  413. ULONG inputBufferLength,
  414. ULONG *outputBufferLength
  415. )
  416. {
  417. NTSTATUS Status;
  418. PGPC_DEREGISTER_CLIENT_REQ GpcReq;
  419. PGPC_DEREGISTER_CLIENT_RES GpcRes;
  420. GPC_HANDLE GpcClientHandle;
  421. if (inputBufferLength < sizeof(GPC_DEREGISTER_CLIENT_REQ)
  422. ||
  423. *outputBufferLength < sizeof(GPC_DEREGISTER_CLIENT_RES)
  424. ) {
  425. return STATUS_BUFFER_TOO_SMALL;
  426. }
  427. GpcReq = (PGPC_DEREGISTER_CLIENT_REQ)ioBuffer;
  428. GpcRes = (PGPC_DEREGISTER_CLIENT_RES)ioBuffer;
  429. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  430. GPC_ENUM_CLIENT_TYPE,
  431. 'PGDC');
  432. if (GpcClientHandle) {
  433. Status = GpcDeregisterClient(GpcClientHandle);
  434. } else {
  435. Status = STATUS_INVALID_HANDLE;
  436. }
  437. if (GpcClientHandle) {
  438. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGDC');
  439. }
  440. ASSERT(Status != GPC_STATUS_PENDING);
  441. GpcRes->Status = Status;
  442. *outputBufferLength = sizeof(GPC_DEREGISTER_CLIENT_RES);
  443. return STATUS_SUCCESS;
  444. }
  445. NTSTATUS
  446. ProxyGpcAddCfInfo(
  447. PVOID ioBuffer,
  448. ULONG inputBufferLength,
  449. ULONG *outputBufferLength,
  450. PIRP Irp
  451. )
  452. {
  453. NTSTATUS Status;
  454. GPC_HANDLE GpcClientHandle;
  455. PGPC_ADD_CF_INFO_REQ GpcReq;
  456. PGPC_ADD_CF_INFO_RES GpcRes;
  457. PBLOB_BLOCK pBlob = NULL;
  458. QUEUED_COMPLETION QItem;
  459. UNICODE_STRING CfInfoName;
  460. USHORT NameLen = 0;
  461. if (inputBufferLength < sizeof(GPC_ADD_CF_INFO_REQ)
  462. ||
  463. *outputBufferLength < sizeof(GPC_ADD_CF_INFO_RES)
  464. ) {
  465. return STATUS_BUFFER_TOO_SMALL;
  466. }
  467. GpcReq = (PGPC_ADD_CF_INFO_REQ)ioBuffer;
  468. GpcRes = (PGPC_ADD_CF_INFO_RES)ioBuffer;
  469. if (GpcReq->CfInfoSize >
  470. inputBufferLength - FIELD_OFFSET(GPC_ADD_CF_INFO_REQ, CfInfo)) {
  471. return STATUS_INVALID_BUFFER_SIZE;
  472. }
  473. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  474. GPC_ENUM_CLIENT_TYPE,
  475. 'PGAC');
  476. if (GpcClientHandle) {
  477. Status = GpcAddCfInfo(GpcClientHandle,
  478. GpcReq->CfInfoSize,
  479. &GpcReq->CfInfo,
  480. GpcReq->ClientCfInfoContext,
  481. (PGPC_HANDLE)&pBlob);
  482. if (NT_SUCCESS(Status)) {
  483. //
  484. // including PENDING
  485. //
  486. if (Status == GPC_STATUS_PENDING) {
  487. QItem.OpCode = OP_ADD_CFINFO;
  488. QItem.ClientHandle = GpcClientHandle;
  489. QItem.CfInfoHandle = (GPC_HANDLE)pBlob;
  490. Status = CheckQueuedCompletion(&QItem, Irp);
  491. }
  492. if (Status == GPC_STATUS_SUCCESS) {
  493. GPC_STATUS st = GPC_STATUS_FAILURE;
  494. GPC_CLIENT_HANDLE NotifiedClientCtx = pBlob->NotifiedClientCtx;
  495. PCLIENT_BLOCK pNotifiedClient = pBlob->pNotifiedClient;
  496. GpcRes->GpcCfInfoHandle = (GPC_HANDLE)AllocateHandle(&pBlob->ClHandle, (PVOID)pBlob);
  497. // what if we cant allocate a handle? fail the add!
  498. if (!GpcRes->GpcCfInfoHandle) {
  499. GpcRemoveCfInfo(GpcClientHandle,
  500. pBlob);
  501. Status = STATUS_INSUFFICIENT_RESOURCES;
  502. goto exit;
  503. }
  504. if (pNotifiedClient) {
  505. if (pNotifiedClient->FuncList.ClGetCfInfoName &&
  506. NotifiedClientCtx) {
  507. st = pNotifiedClient->FuncList.ClGetCfInfoName(
  508. pNotifiedClient->ClientCtx,
  509. NotifiedClientCtx,
  510. &CfInfoName
  511. );
  512. if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
  513. CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
  514. //
  515. // RajeshSu claims this can never happen.
  516. //
  517. ASSERT(NT_SUCCESS(st));
  518. }
  519. }
  520. if (NT_SUCCESS(st)) {
  521. //
  522. // copy the instance name
  523. //
  524. GpcRes->InstanceNameLength = NameLen = CfInfoName.Length;
  525. RtlMoveMemory(GpcRes->InstanceName,
  526. CfInfoName.Buffer,
  527. CfInfoName.Length
  528. );
  529. } else {
  530. //
  531. // generate a default name
  532. //
  533. if (NotifiedClientCtx)
  534. swprintf(GpcRes->InstanceName, L"Flow %08X", NotifiedClientCtx);
  535. else
  536. swprintf(GpcRes->InstanceName, L"Flow <unkonwn name>");
  537. GpcRes->InstanceNameLength = NameLen = wcslen(GpcRes->InstanceName)*sizeof(WCHAR);
  538. }
  539. GpcRes->InstanceName[GpcRes->InstanceNameLength/sizeof(WCHAR)] = L'\0';
  540. } else {
  541. pBlob = NULL;
  542. }
  543. }
  544. //
  545. // release the ref count we got earlier
  546. //
  547. exit:
  548. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAC');
  549. } else {
  550. ASSERT(pBlob == NULL);
  551. Status = GPC_STATUS_INVALID_HANDLE;
  552. }
  553. GpcRes->InstanceNameLength = NameLen;
  554. GpcRes->Status = Status;
  555. *outputBufferLength = sizeof(GPC_ADD_CF_INFO_RES);
  556. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  557. }
  558. NTSTATUS
  559. ProxyGpcAddPattern(
  560. PVOID ioBuffer,
  561. ULONG inputBufferLength,
  562. ULONG *outputBufferLength
  563. )
  564. {
  565. NTSTATUS Status;
  566. GPC_HANDLE GpcClientHandle;
  567. GPC_HANDLE GpcCfInfoHandle;
  568. CLASSIFICATION_HANDLE ClassificationHandle;
  569. PGPC_ADD_PATTERN_REQ GpcReq;
  570. PGPC_ADD_PATTERN_RES GpcRes;
  571. PVOID Pattern;
  572. PVOID Mask;
  573. PPATTERN_BLOCK pPattern;
  574. if (inputBufferLength < sizeof(GPC_ADD_PATTERN_REQ)
  575. ||
  576. *outputBufferLength < sizeof(GPC_ADD_PATTERN_RES)
  577. ) {
  578. return STATUS_BUFFER_TOO_SMALL;
  579. }
  580. GpcReq = (PGPC_ADD_PATTERN_REQ)ioBuffer;
  581. GpcRes = (PGPC_ADD_PATTERN_RES)ioBuffer;
  582. if (GpcReq->PatternSize > MAX_PATTERN_SIZE) {
  583. return STATUS_INVALID_PARAMETER;
  584. }
  585. if (inputBufferLength - FIELD_OFFSET(GPC_ADD_PATTERN_REQ, PatternAndMask)
  586. < 2 * GpcReq->PatternSize) {
  587. return STATUS_BUFFER_TOO_SMALL;
  588. }
  589. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  590. GPC_ENUM_CLIENT_TYPE,
  591. 'PGAP');
  592. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle,
  593. GPC_ENUM_CFINFO_TYPE,
  594. 'PGAP');
  595. if (GpcClientHandle && GpcCfInfoHandle) {
  596. Pattern = (PVOID)&GpcReq->PatternAndMask;
  597. Mask = (PVOID)((PCHAR)(&GpcReq->PatternAndMask) + GpcReq->PatternSize);
  598. Status = GpcAddPattern(GpcClientHandle,
  599. GpcReq->ProtocolTemplate,
  600. Pattern,
  601. Mask,
  602. GpcReq->Priority,
  603. GpcCfInfoHandle,
  604. (PGPC_HANDLE)&pPattern,
  605. &ClassificationHandle);
  606. if (Status == GPC_STATUS_SUCCESS) {
  607. ASSERT(Pattern);
  608. GpcRes->GpcPatternHandle = AllocateHandle(&pPattern->ClHandle, (PVOID)pPattern);
  609. //
  610. // In certain circs, alloc_HF_handle could return 0.
  611. // check for that and clean up the mess.
  612. //
  613. if (!GpcRes->GpcPatternHandle) {
  614. //
  615. // remove the pattern that was just added.
  616. //
  617. Status = GpcRemovePattern(GpcClientHandle,
  618. pPattern);
  619. //
  620. // This was really the problem why we got a NULL handle
  621. //
  622. Status = STATUS_INSUFFICIENT_RESOURCES;
  623. }
  624. }
  625. } else {
  626. //
  627. // Something went wrong and we dont know WHAT!!
  628. //
  629. Status = STATUS_INVALID_HANDLE;
  630. }
  631. if (GpcCfInfoHandle) {
  632. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGAP');
  633. }
  634. if (GpcClientHandle) {
  635. //
  636. // release the ref count we got earlier
  637. //
  638. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAP');
  639. }
  640. ASSERT(Status != GPC_STATUS_PENDING);
  641. GpcRes->Status = Status;
  642. GpcRes->ClassificationHandle = ClassificationHandle;
  643. *outputBufferLength = sizeof(GPC_ADD_PATTERN_RES);
  644. return STATUS_SUCCESS;
  645. }
  646. NTSTATUS
  647. ProxyGpcModifyCfInfo(
  648. PVOID ioBuffer,
  649. ULONG inputBufferLength,
  650. ULONG *outputBufferLength,
  651. PIRP Irp
  652. )
  653. {
  654. NTSTATUS Status;
  655. GPC_HANDLE GpcClientHandle;
  656. GPC_HANDLE GpcCfInfoHandle;
  657. PGPC_MODIFY_CF_INFO_REQ GpcReq;
  658. PGPC_MODIFY_CF_INFO_RES GpcRes;
  659. QUEUED_COMPLETION QItem;
  660. if (inputBufferLength < sizeof(GPC_MODIFY_CF_INFO_REQ)
  661. ||
  662. *outputBufferLength < sizeof(GPC_MODIFY_CF_INFO_RES)
  663. ) {
  664. return STATUS_BUFFER_TOO_SMALL;
  665. }
  666. GpcReq = (PGPC_MODIFY_CF_INFO_REQ)ioBuffer;
  667. GpcRes = (PGPC_MODIFY_CF_INFO_RES)ioBuffer;
  668. if (GpcReq->CfInfoSize >
  669. inputBufferLength - FIELD_OFFSET(GPC_MODIFY_CF_INFO_REQ, CfInfo)) {
  670. return STATUS_INVALID_BUFFER_SIZE;
  671. }
  672. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  673. GPC_ENUM_CLIENT_TYPE,
  674. 'PGMP');
  675. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle,
  676. GPC_ENUM_CFINFO_TYPE,
  677. 'PGMP');
  678. if (GpcClientHandle && GpcCfInfoHandle) {
  679. Status = GpcModifyCfInfo(GpcClientHandle,
  680. GpcCfInfoHandle,
  681. GpcReq->CfInfoSize,
  682. &GpcReq->CfInfo
  683. );
  684. if (Status == GPC_STATUS_PENDING) {
  685. QItem.OpCode = OP_MODIFY_CFINFO;
  686. QItem.ClientHandle = GpcClientHandle;
  687. QItem.CfInfoHandle = GpcCfInfoHandle;
  688. Status = CheckQueuedCompletion(&QItem, Irp);
  689. }
  690. } else {
  691. Status = STATUS_INVALID_HANDLE;
  692. }
  693. if (GpcCfInfoHandle) {
  694. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGMP');
  695. }
  696. if (GpcClientHandle) {
  697. //
  698. // release the ref count we got earlier
  699. //
  700. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGMP');
  701. }
  702. GpcRes->Status = Status;
  703. *outputBufferLength = sizeof(GPC_MODIFY_CF_INFO_RES);
  704. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  705. }
  706. NTSTATUS
  707. ProxyGpcRemoveCfInfo(
  708. PVOID ioBuffer,
  709. ULONG inputBufferLength,
  710. ULONG *outputBufferLength,
  711. PIRP Irp
  712. )
  713. {
  714. NTSTATUS Status;
  715. GPC_HANDLE GpcClientHandle;
  716. GPC_HANDLE GpcCfInfoHandle;
  717. PGPC_REMOVE_CF_INFO_REQ GpcReq;
  718. PGPC_REMOVE_CF_INFO_RES GpcRes;
  719. QUEUED_COMPLETION QItem;
  720. if (inputBufferLength < sizeof(GPC_REMOVE_CF_INFO_REQ)
  721. ||
  722. *outputBufferLength < sizeof(GPC_REMOVE_CF_INFO_RES)
  723. ) {
  724. return STATUS_BUFFER_TOO_SMALL;
  725. }
  726. GpcReq = (PGPC_REMOVE_CF_INFO_REQ)ioBuffer;
  727. GpcRes = (PGPC_REMOVE_CF_INFO_RES)ioBuffer;
  728. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  729. GPC_ENUM_CLIENT_TYPE,
  730. 'PGRC');
  731. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle,
  732. GPC_ENUM_CFINFO_TYPE,
  733. 'PGRC');
  734. if (GpcClientHandle && GpcCfInfoHandle) {
  735. Status = privateGpcRemoveCfInfo(GpcClientHandle,
  736. GpcCfInfoHandle,
  737. GPC_FLAGS_USERMODE_CLIENT );
  738. if (Status == GPC_STATUS_PENDING) {
  739. QItem.OpCode = OP_REMOVE_CFINFO;
  740. QItem.ClientHandle = GpcClientHandle;
  741. QItem.CfInfoHandle = GpcCfInfoHandle;
  742. Status = CheckQueuedCompletion(&QItem, Irp);
  743. }
  744. } else {
  745. Status = STATUS_INVALID_HANDLE;
  746. }
  747. if (GpcCfInfoHandle) {
  748. //
  749. // release the ref count we got earlier
  750. //
  751. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGRC');
  752. }
  753. if (GpcClientHandle) {
  754. //
  755. // release the ref count we got earlier
  756. //
  757. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGRC');
  758. }
  759. GpcRes->Status = Status;
  760. *outputBufferLength = sizeof(GPC_REMOVE_CF_INFO_RES);
  761. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  762. }
  763. NTSTATUS
  764. ProxyGpcRemovePattern(
  765. PVOID ioBuffer,
  766. ULONG inputBufferLength,
  767. ULONG *outputBufferLength
  768. )
  769. {
  770. NTSTATUS Status;
  771. GPC_HANDLE GpcClientHandle;
  772. GPC_HANDLE GpcPatternHandle;
  773. PGPC_REMOVE_PATTERN_REQ GpcReq;
  774. PGPC_REMOVE_PATTERN_RES GpcRes;
  775. if (inputBufferLength < sizeof(GPC_REMOVE_PATTERN_REQ)
  776. ||
  777. *outputBufferLength < sizeof(GPC_REMOVE_PATTERN_RES)
  778. ) {
  779. return STATUS_BUFFER_TOO_SMALL;
  780. }
  781. GpcReq = (PGPC_REMOVE_PATTERN_REQ)ioBuffer;
  782. GpcRes = (PGPC_REMOVE_PATTERN_RES)ioBuffer;
  783. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  784. GPC_ENUM_CLIENT_TYPE,
  785. 'PGRP');
  786. GpcPatternHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcPatternHandle,
  787. GPC_ENUM_PATTERN_TYPE,
  788. 'PGRP');
  789. if (GpcClientHandle && GpcPatternHandle) {
  790. Status = GpcRemovePattern(GpcClientHandle,
  791. GpcPatternHandle);
  792. } else {
  793. //
  794. // Something is wrong. Set the status to invalid handle!
  795. //
  796. Status = STATUS_INVALID_HANDLE;
  797. }
  798. if (GpcPatternHandle) {
  799. REFDEL(&((PPATTERN_BLOCK)GpcPatternHandle)->RefCount, 'PGRP');
  800. }
  801. if (GpcClientHandle) {
  802. //
  803. // release the ref count we got earlier
  804. //
  805. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGRP');
  806. }
  807. ASSERT(Status != GPC_STATUS_PENDING);
  808. GpcRes->Status = Status;
  809. *outputBufferLength = sizeof(GPC_REMOVE_PATTERN_RES);
  810. return STATUS_SUCCESS;
  811. }
  812. NTSTATUS
  813. ProxyGpcEnumCfInfo(
  814. PVOID ioBuffer,
  815. ULONG inputBufferLength,
  816. ULONG *outputBufferLength
  817. )
  818. {
  819. NTSTATUS Status;
  820. PGPC_ENUM_CFINFO_REQ GpcReq;
  821. PGPC_ENUM_CFINFO_RES GpcRes;
  822. ULONG Size;
  823. ULONG TotalCount;
  824. GPC_HANDLE GpcClientHandle;
  825. GPC_HANDLE GpcCfInfoHandle;
  826. GPC_HANDLE EnumHandle;
  827. PBLOB_BLOCK pBlob;
  828. if (inputBufferLength < sizeof(GPC_ENUM_CFINFO_REQ)
  829. ||
  830. *outputBufferLength < sizeof(GPC_ENUM_CFINFO_RES)
  831. ) {
  832. return STATUS_BUFFER_TOO_SMALL;
  833. }
  834. GpcReq = (PGPC_ENUM_CFINFO_REQ)ioBuffer;
  835. GpcRes = (PGPC_ENUM_CFINFO_RES)ioBuffer;
  836. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  837. GPC_ENUM_CLIENT_TYPE,
  838. 'PGEC');
  839. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->EnumHandle,
  840. GPC_ENUM_CFINFO_TYPE,
  841. 'PGEC');
  842. if (GpcReq->EnumHandle != NULL && GpcCfInfoHandle == NULL) {
  843. //
  844. // the flow has been deleted during enumeration
  845. //
  846. Status = STATUS_DATA_ERROR;
  847. } else if (GpcClientHandle) {
  848. TotalCount = GpcReq->CfInfoCount;
  849. EnumHandle = GpcReq->EnumHandle;
  850. Size = *outputBufferLength - FIELD_OFFSET(GPC_ENUM_CFINFO_RES,
  851. EnumBuffer);
  852. //
  853. // save the blob pointer with the one extra ref count
  854. // since we called GetHandleObjectWithRef
  855. //
  856. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  857. Status = GpcEnumCfInfo(GpcClientHandle,
  858. &GpcCfInfoHandle,
  859. &EnumHandle,
  860. &TotalCount,
  861. &Size,
  862. GpcRes->EnumBuffer
  863. );
  864. if (pBlob) {
  865. REFDEL(&pBlob->RefCount, 'PGEC');
  866. }
  867. if (Status == GPC_STATUS_SUCCESS) {
  868. //
  869. // fill in the results
  870. //
  871. GpcRes->TotalCfInfo = TotalCount;
  872. GpcRes->EnumHandle = EnumHandle;
  873. *outputBufferLength = Size + FIELD_OFFSET(GPC_ENUM_CFINFO_RES,
  874. EnumBuffer);
  875. }
  876. } else {
  877. if (GpcCfInfoHandle) {
  878. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGEC');
  879. }
  880. Status = STATUS_INVALID_HANDLE;
  881. }
  882. if (GpcClientHandle) {
  883. //
  884. // release the ref count we got earlier
  885. //
  886. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGEC');
  887. }
  888. ASSERT(Status != GPC_STATUS_PENDING);
  889. GpcRes->Status = Status;
  890. return STATUS_SUCCESS;
  891. }
  892. VOID
  893. CancelPendingIrpCfInfo(
  894. IN PDEVICE_OBJECT Device,
  895. IN PIRP Irp
  896. )
  897. /*++
  898. Routine Description:
  899. Cancels an outstanding IRP request for a CfInfo request.
  900. Arguments:
  901. Device - The device on which the request was issued.
  902. Irp - Pointer to I/O request packet to cancel.
  903. Return Value:
  904. None
  905. Notes:
  906. This function is called with cancel spinlock held. It must be
  907. released before the function returns.
  908. The cfinfo block associated with this request cannot be
  909. freed until the request completes. The completion routine will
  910. free it.
  911. --*/
  912. {
  913. PPENDING_IRP pPendingIrp = NULL;
  914. PPENDING_IRP pItem;
  915. PLIST_ENTRY pEntry;
  916. #if DBG
  917. KIRQL irql = KeGetCurrentIrql();
  918. HANDLE thrd = PsGetCurrentThreadId();
  919. #endif
  920. DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: Irp=0x%X\n",
  921. (ULONG_PTR)Irp));
  922. TRACE(IOCTL, Irp, 0, "CancelPendingIrpCfInfo:");
  923. TRACE(LOCKS, thrd, irql, "CancelPendingIrpCfInfo:");
  924. for ( pEntry = PendingIrpCfInfoList.Flink;
  925. pEntry != &PendingIrpCfInfoList;
  926. pEntry = pEntry->Flink ) {
  927. pItem = CONTAINING_RECORD(pEntry, PENDING_IRP, Linkage);
  928. if (pItem->Irp == Irp) {
  929. pPendingIrp = pItem;
  930. GpcRemoveEntryList(pEntry);
  931. IoSetCancelRoutine(pPendingIrp->Irp, NULL);
  932. break;
  933. }
  934. }
  935. IoReleaseCancelSpinLock(Irp->CancelIrql);
  936. if (pPendingIrp != NULL) {
  937. DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: found PendingIrp=0x%X\n",
  938. (ULONG_PTR)pPendingIrp));
  939. TRACE(IOCTL, Irp, pPendingIrp, "CancelPendingIrpCfInfo.PendingIrp:");
  940. //
  941. // Free the PENDING_IRP structure. The control block will be freed
  942. // when the request completes.
  943. //
  944. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  945. //
  946. // Complete the IRP.
  947. //
  948. Irp->IoStatus.Information = 0;
  949. Irp->IoStatus.Status = STATUS_CANCELLED;
  950. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  951. } else {
  952. DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: PendingIrp not found\n"));
  953. TRACE(IOCTL, Irp, 0, "CancelPendingIrpCfInfo.NoPendingIrp:");
  954. }
  955. #if DBG
  956. irql = KeGetCurrentIrql();
  957. #endif
  958. TRACE(LOCKS, thrd, irql, "CancelPendingIrpCfInfo (end)");
  959. return;
  960. }
  961. VOID
  962. CancelPendingIrpNotify(
  963. IN PDEVICE_OBJECT Device,
  964. IN PIRP Irp
  965. )
  966. /*++
  967. Routine Description:
  968. Cancels an outstanding IRP request for a notification.
  969. Arguments:
  970. Device - The device on which the request was issued.
  971. Irp - Pointer to I/O request packet to cancel.
  972. Return Value:
  973. None
  974. Notes:
  975. This function is called with cancel spinlock held. It must be
  976. released before the function returns.
  977. --*/
  978. {
  979. PPENDING_IRP pPendingIrp = NULL;
  980. PPENDING_IRP pItem;
  981. PLIST_ENTRY pEntry;
  982. #if DBG
  983. KIRQL irql = KeGetCurrentIrql();
  984. HANDLE thrd = PsGetCurrentThreadId();
  985. #endif
  986. DBGPRINT(IOCTL, ("CancelPendingIrpNotify: Irp=0x%X\n",
  987. (ULONG_PTR)Irp));
  988. TRACE(IOCTL, Irp, 0, "CancelPendingIrpNotify:");
  989. TRACE(LOCKS, thrd, irql, "CancelPendingIrpNotify:");
  990. for ( pEntry = PendingIrpNotifyList.Flink;
  991. pEntry != &PendingIrpNotifyList;
  992. pEntry = pEntry->Flink ) {
  993. pItem = CONTAINING_RECORD(pEntry, PENDING_IRP, Linkage);
  994. if (pItem->Irp == Irp) {
  995. pPendingIrp = pItem;
  996. GpcRemoveEntryList(pEntry);
  997. IoSetCancelRoutine(pPendingIrp->Irp, NULL);
  998. break;
  999. }
  1000. }
  1001. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1002. if (pPendingIrp != NULL) {
  1003. DBGPRINT(IOCTL, ("CancelPendingIrpNotify: Found a PendingIrp=0x%X\n",
  1004. (ULONG_PTR)pPendingIrp));
  1005. TRACE(IOCTL, Irp, pPendingIrp, "CancelPendingIrpNotify.PendingIrp:");
  1006. //
  1007. // Free the PENDING_IRP structure.
  1008. //
  1009. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1010. //
  1011. // Complete the IRP.
  1012. //
  1013. Irp->IoStatus.Information = 0;
  1014. Irp->IoStatus.Status = STATUS_CANCELLED;
  1015. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1016. } else {
  1017. DBGPRINT(IOCTL, ("CancelPendingIrpNotify: PendingIrp not found\n"));
  1018. TRACE(IOCTL, Irp, 0, "CancelPendingIrpNotify.NoPendingIrp:");
  1019. }
  1020. #if DBG
  1021. irql = KeGetCurrentIrql();
  1022. #endif
  1023. TRACE(LOCKS, thrd, irql, "CancelPendingIrpNotify (end)");
  1024. return;
  1025. }
  1026. VOID
  1027. UMClientRemoveCfInfoNotify(
  1028. IN PCLIENT_BLOCK pClient,
  1029. IN PBLOB_BLOCK pBlob
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. Notify user mode client that the CfInfo is deleted.
  1034. This will dequeue a pending IRP and will complete it.
  1035. If there is no pending IRP, a GPC_NOTIFY_REQUEST_RES buffer
  1036. will be queued until we get an IRP down the stack.
  1037. Arguments:
  1038. pClient - the notified client
  1039. pBlob - the deleted cfinfo
  1040. Return Value:
  1041. None
  1042. --*/
  1043. {
  1044. KIRQL oldIrql;
  1045. PIRP pIrp;
  1046. PPENDING_IRP pPendingIrp = NULL;
  1047. PLIST_ENTRY pEntry;
  1048. PQUEUED_NOTIFY pQItem;
  1049. PGPC_NOTIFY_REQUEST_RES GpcRes;
  1050. ASSERT(pClient == pBlob->pOwnerClient);
  1051. DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: pClient=0x%X, pBlob=0x%X\n",
  1052. (ULONG_PTR)pClient, (ULONG_PTR)pBlob));
  1053. TRACE(IOCTL, pClient, pBlob, "UMClientRemoveCfInfoNotify:");
  1054. //
  1055. // Find the request IRP on the pending list.
  1056. //
  1057. IoAcquireCancelSpinLock(&oldIrql);
  1058. for ( pEntry = PendingIrpNotifyList.Flink;
  1059. pEntry != &PendingIrpNotifyList;
  1060. pEntry = pEntry->Flink ) {
  1061. pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
  1062. if (pPendingIrp->FileObject == pClient->pFileObject) {
  1063. //
  1064. // that's the pending request
  1065. //
  1066. pIrp = pPendingIrp->Irp;
  1067. IoSetCancelRoutine(pIrp, NULL);
  1068. GpcRemoveEntryList(pEntry);
  1069. break;
  1070. } else {
  1071. pPendingIrp = NULL;
  1072. }
  1073. }
  1074. if (pPendingIrp == NULL) {
  1075. //
  1076. // No IRP, we need to queue the notification block
  1077. //
  1078. DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: No pending IRP found\n"
  1079. ));
  1080. TRACE(IOCTL,
  1081. pClient->ClientCtx,
  1082. pBlob->arClientCtx[pClient->AssignedIndex],
  1083. "UMClientRemoveCfInfoNotify.NoPendingIrp:");
  1084. GpcAllocFromLL(&pQItem, &QueuedNotificationLL, QueuedNotificationTag);
  1085. if (pQItem) {
  1086. pQItem->FileObject = pClient->pFileObject;
  1087. //
  1088. // fill the item
  1089. //
  1090. pQItem->NotifyRes.ClientCtx = pClient->ClientCtx;
  1091. pQItem->NotifyRes.NotificationCtx =
  1092. (ULONG_PTR)pBlob->arClientCtx[pClient->AssignedIndex];
  1093. pQItem->NotifyRes.SubCode = GPC_NOTIFY_CFINFO_CLOSED;
  1094. pQItem->NotifyRes.Reason = 0; // for now...
  1095. pQItem->NotifyRes.Param1 = 0; // for now...
  1096. GpcInsertTailList(&QueuedNotificationList, &pQItem->Linkage);
  1097. }
  1098. }
  1099. IoReleaseCancelSpinLock(oldIrql);
  1100. if (pPendingIrp) {
  1101. //
  1102. // found an IRP, fill and complete
  1103. //
  1104. DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: Pending IRP found=0x%X\n",
  1105. (ULONG_PTR)pIrp));
  1106. TRACE(IOCTL,
  1107. pClient->ClientCtx,
  1108. pBlob->arClientCtx[pClient->AssignedIndex],
  1109. "UMClientRemoveCfInfoNotify.PendingIrp:");
  1110. GpcRes = (PGPC_NOTIFY_REQUEST_RES)pIrp->AssociatedIrp.SystemBuffer;
  1111. GpcRes->ClientCtx = pClient->ClientCtx;
  1112. GpcRes->NotificationCtx =
  1113. (ULONG_PTR)pBlob->arClientCtx[pClient->AssignedIndex];
  1114. GpcRes->SubCode = GPC_NOTIFY_CFINFO_CLOSED;
  1115. GpcRes->Reason = 0; // for now...
  1116. GpcRes->Param1 = 0; // for now...
  1117. //
  1118. // complete the IRP
  1119. //
  1120. pIrp->IoStatus.Information = sizeof(GPC_NOTIFY_REQUEST_REQ);
  1121. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1122. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1123. //
  1124. // We can free the pending irp item
  1125. //
  1126. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1127. }
  1128. //
  1129. // for now - complete the operation
  1130. // we should probably let the User Mode client do it,
  1131. // but this complicates things a little...
  1132. //
  1133. GpcRemoveCfInfoNotifyComplete((GPC_HANDLE)pClient,
  1134. (GPC_HANDLE)pBlob,
  1135. GPC_STATUS_SUCCESS
  1136. );
  1137. return;
  1138. }
  1139. VOID
  1140. UMCfInfoComplete(
  1141. IN GPC_COMPLETION_OP OpCode,
  1142. IN PCLIENT_BLOCK pClient,
  1143. IN PBLOB_BLOCK pBlob,
  1144. IN GPC_STATUS Status
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. This is the completion routine for any pending CfInfo request.
  1149. It will search the pending IRP CfInfo list for a matching CfInfo
  1150. structure that has been stored while the Add, Modify or Remove
  1151. request returned PENDING. The client must be the CfInfo owner,
  1152. otherwise we would have never got here.
  1153. If an IRP is not found, it means the operation completed *before*
  1154. we got back the PENDING status, which is perfectly legal.
  1155. In this case, we queue a completion item and return.
  1156. Arguments:
  1157. OpCode - the code of the completion (add, modify or remove)
  1158. pClient - the notified client
  1159. pBlob - the deleted cfinfo
  1160. Status - the reported status
  1161. Return Value:
  1162. None
  1163. --*/
  1164. {
  1165. typedef union _GPC_CF_INFO_RES {
  1166. GPC_ADD_CF_INFO_RES AddRes;
  1167. GPC_MODIFY_CF_INFO_RES ModifyRes;
  1168. GPC_REMOVE_CF_INFO_RES RemoveRes;
  1169. } GPC_CF_INFO_RES;
  1170. KIRQL oldIrql;
  1171. PIRP pIrp;
  1172. PIO_STACK_LOCATION pIrpSp;
  1173. PPENDING_IRP pPendingIrp = NULL;
  1174. PLIST_ENTRY pEntry;
  1175. GPC_CF_INFO_RES *GpcRes;
  1176. ULONG outputBuferLength;
  1177. //PQUEUED_COMPLETION pQItem;
  1178. //ASSERT(pClient == pBlob->pOwnerClient);
  1179. DBGPRINT(IOCTL, ("UMCfInfoComplete: pClient=0x%X, pBlob=0x%X, Status=0x%X\n",
  1180. (ULONG_PTR)pClient, (ULONG_PTR)pBlob, Status));
  1181. TRACE(IOCTL, OpCode, pClient, "UMCfInfoComplete:");
  1182. TRACE(IOCTL, pBlob, Status, "UMCfInfoComplete:");
  1183. //
  1184. // Find the request IRP on the pending list.
  1185. //
  1186. IoAcquireCancelSpinLock(&oldIrql);
  1187. for ( pEntry = PendingIrpCfInfoList.Flink;
  1188. pEntry != &PendingIrpCfInfoList;
  1189. pEntry = pEntry->Flink ) {
  1190. pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
  1191. if (pPendingIrp->QComp.CfInfoHandle == (GPC_HANDLE)pBlob
  1192. &&
  1193. pPendingIrp->QComp.OpCode == OpCode ) {
  1194. //
  1195. // that's the pending request
  1196. //
  1197. pIrp = pPendingIrp->Irp;
  1198. ASSERT(pIrp);
  1199. IoSetCancelRoutine(pIrp, NULL);
  1200. GpcRemoveEntryList(pEntry);
  1201. break;
  1202. } else {
  1203. pPendingIrp = NULL;
  1204. }
  1205. }
  1206. if (pPendingIrp == NULL) {
  1207. //
  1208. // No IRP, we need to queue a completion block
  1209. //
  1210. DBGPRINT(IOCTL, ("UMCfInfoComplete: No pending IRP found\n"));
  1211. TRACE(IOCTL, pBlob, Status, "UMCfInfoComplete.NoPendingIrp:");
  1212. GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1213. if (pPendingIrp) {
  1214. pPendingIrp->Irp = NULL;
  1215. pPendingIrp->FileObject = pClient->pFileObject;
  1216. pPendingIrp->QComp.OpCode = OpCode;
  1217. pPendingIrp->QComp.ClientHandle = (GPC_HANDLE)pClient;
  1218. pPendingIrp->QComp.CfInfoHandle = (GPC_HANDLE)pBlob;
  1219. pPendingIrp->QComp.Status = Status;
  1220. GpcInsertTailList(&QueuedCompletionList, &pPendingIrp->Linkage);
  1221. }
  1222. IoReleaseCancelSpinLock(oldIrql);
  1223. return;
  1224. }
  1225. IoReleaseCancelSpinLock(oldIrql);
  1226. ASSERT(pPendingIrp && pIrp);
  1227. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1228. GpcRes = (GPC_CF_INFO_RES *)pIrp->AssociatedIrp.SystemBuffer;
  1229. DBGPRINT(IOCTL, ("UMCfInfoComplete: Pending IRP found=0x%X, Ioctl=0x%X\n",
  1230. (ULONG_PTR)pIrp,
  1231. pIrpSp->Parameters.DeviceIoControl.IoControlCode
  1232. ));
  1233. TRACE(IOCTL,
  1234. pIrp,
  1235. pIrpSp->Parameters.DeviceIoControl.IoControlCode,
  1236. "UMCfInfoComplete.PendingIrp:");
  1237. switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
  1238. case IOCTL_GPC_ADD_CF_INFO:
  1239. ASSERT(OpCode == OP_ADD_CFINFO);
  1240. ASSERT(pBlob->State == GPC_STATE_ADD);
  1241. GpcRes->AddRes.Status = Status;
  1242. GpcRes->AddRes.ClientCtx = pClient->ClientCtx;
  1243. GpcRes->AddRes.CfInfoCtx = pBlob->OwnerClientCtx;
  1244. GpcRes->AddRes.GpcCfInfoHandle = pBlob->ClHandle;
  1245. if (Status == GPC_STATUS_SUCCESS) {
  1246. UNICODE_STRING CfInfoName;
  1247. if (pBlob->pNotifiedClient) {
  1248. GPC_STATUS st = GPC_STATUS_FAILURE;
  1249. if (pBlob->pNotifiedClient->FuncList.ClGetCfInfoName) {
  1250. ASSERT(pBlob->NotifiedClientCtx);
  1251. pBlob->pNotifiedClient->FuncList.ClGetCfInfoName(
  1252. pBlob->pNotifiedClient->ClientCtx,
  1253. pBlob->NotifiedClientCtx,
  1254. &CfInfoName
  1255. );
  1256. if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
  1257. CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
  1258. }
  1259. if (!NT_SUCCESS(st)) {
  1260. //
  1261. // generate a default name
  1262. //
  1263. swprintf(CfInfoName.Buffer, L"Flow %08X", pBlob->NotifiedClientCtx);
  1264. CfInfoName.Length = wcslen(CfInfoName.Buffer)*sizeof(WCHAR);
  1265. }
  1266. //
  1267. // copy the instance name
  1268. //
  1269. GpcRes->AddRes.InstanceNameLength = CfInfoName.Length;
  1270. NdisMoveMemory(GpcRes->AddRes.InstanceName,
  1271. CfInfoName.Buffer,
  1272. CfInfoName.Length
  1273. );
  1274. }
  1275. }
  1276. outputBuferLength = sizeof(GPC_ADD_CF_INFO_RES);
  1277. break;
  1278. case IOCTL_GPC_MODIFY_CF_INFO:
  1279. ASSERT(OpCode == OP_MODIFY_CFINFO);
  1280. ASSERT(pBlob->State == GPC_STATE_MODIFY);
  1281. GpcRes->ModifyRes.Status = Status;
  1282. GpcRes->ModifyRes.ClientCtx = pClient->ClientCtx;
  1283. GpcRes->ModifyRes.CfInfoCtx = pBlob->OwnerClientCtx;
  1284. outputBuferLength = sizeof(GPC_MODIFY_CF_INFO_RES);
  1285. break;
  1286. case IOCTL_GPC_REMOVE_CF_INFO:
  1287. ASSERT(OpCode == OP_REMOVE_CFINFO);
  1288. ASSERT(pBlob->State == GPC_STATE_REMOVE);
  1289. GpcRes->RemoveRes.Status = Status;
  1290. GpcRes->RemoveRes.ClientCtx = pClient->ClientCtx;
  1291. GpcRes->RemoveRes.CfInfoCtx = pBlob->OwnerClientCtx;
  1292. outputBuferLength = sizeof(GPC_REMOVE_CF_INFO_RES);
  1293. break;
  1294. default:
  1295. ASSERT(0);
  1296. }
  1297. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1298. //
  1299. // Complete the IRP.
  1300. //
  1301. pIrp->IoStatus.Information = outputBuferLength;
  1302. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1303. DBGPRINT(IOCTL, ("UMCfInfoComplete: Completing IRP =0x%X, Status=0x%X\n",
  1304. (ULONG_PTR)pIrp, Status ));
  1305. TRACE(IOCTL, pIrp, Status, "UMCfInfoComplete.Completing:");
  1306. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1307. return;
  1308. }
  1309. NTSTATUS
  1310. CheckQueuedNotification(
  1311. IN PIRP Irp,
  1312. IN OUT ULONG *outputBufferLength
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. This routine will check for a queued notification structrue,
  1317. and it will fill the ioBuffer in the IRP if one has been found
  1318. and return STATUS_SUCCESS. This should cover the case where
  1319. the IRP was not available when the notification was generated.
  1320. O/w the routine returns STATUS_PENDING.
  1321. Arguments:
  1322. Irp - the incoming IRP
  1323. Return Value:
  1324. STATUS_SUCCESS or STATUS_PENDING
  1325. --*/
  1326. {
  1327. KIRQL oldIrql;
  1328. PIO_STACK_LOCATION pIrpSp;
  1329. PQUEUED_NOTIFY pQItem = NULL;
  1330. PLIST_ENTRY pEntry;
  1331. NTSTATUS Status;
  1332. PPENDING_IRP pPendingIrp;
  1333. DBGPRINT(IOCTL, ("CheckQueuedNotification: IRP =0x%X\n",
  1334. (ULONG_PTR)Irp));
  1335. TRACE(IOCTL, Irp, 0, "CheckQueuedNotification:");
  1336. if (*outputBufferLength < sizeof(GPC_NOTIFY_REQUEST_RES)) {
  1337. return STATUS_BUFFER_TOO_SMALL;
  1338. }
  1339. pIrpSp = IoGetCurrentIrpStackLocation(Irp);
  1340. IoAcquireCancelSpinLock(&oldIrql);
  1341. for ( pEntry = QueuedNotificationList.Flink;
  1342. pEntry != &QueuedNotificationList;
  1343. pEntry = pEntry->Flink ) {
  1344. pQItem = CONTAINING_RECORD( pEntry, QUEUED_NOTIFY, Linkage);
  1345. if (pQItem->FileObject == pIrpSp->FileObject) {
  1346. //
  1347. // the queued item if for this file object
  1348. //
  1349. GpcRemoveEntryList(pEntry);
  1350. break;
  1351. } else {
  1352. pQItem = NULL;
  1353. }
  1354. }
  1355. if (pQItem) {
  1356. //
  1357. // We found something on the queue, copy it to the IRP
  1358. // and delete the item
  1359. //
  1360. DBGPRINT(IOCTL, ("CheckQueuedNotification: found QItem =0x%X\n",
  1361. (ULONG_PTR)pQItem));
  1362. TRACE(IOCTL,
  1363. pQItem,
  1364. pQItem->NotifyRes.ClientCtx,
  1365. "CheckQueuedNotification.QItem:");
  1366. ASSERT(*outputBufferLength >= sizeof(GPC_NOTIFY_REQUEST_RES));
  1367. NdisMoveMemory(Irp->AssociatedIrp.SystemBuffer,
  1368. &pQItem->NotifyRes,
  1369. sizeof(GPC_NOTIFY_REQUEST_RES) );
  1370. GpcFreeToLL(pQItem, &QueuedNotificationLL, QueuedNotificationTag);
  1371. *outputBufferLength = sizeof(GPC_NOTIFY_REQUEST_RES);
  1372. Status = STATUS_SUCCESS;
  1373. } else {
  1374. DBGPRINT(IOCTL, ("CheckQueuedNotification: QItem not found...PENDING\n"
  1375. ));
  1376. TRACE(IOCTL, 0, 0, "CheckQueuedNotification.NoQItem:");
  1377. GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1378. if (pPendingIrp != NULL) {
  1379. //
  1380. // add the IRP on the pending notification list
  1381. //
  1382. DBGPRINT(IOCTL, ("CheckQueuedNotification: adding IRP=0x%X to list=0x%X\n",
  1383. (ULONG_PTR)Irp, (ULONG_PTR)pIrpSp ));
  1384. TRACE(IOCTL, Irp, pIrpSp, "CheckQueuedNotification.Irp:");
  1385. pPendingIrp->Irp = Irp;
  1386. pPendingIrp->FileObject = pIrpSp->FileObject;
  1387. if (!Irp->Cancel) {
  1388. IoSetCancelRoutine(Irp, CancelPendingIrpNotify);
  1389. GpcInsertTailList(&PendingIrpNotifyList, &(pPendingIrp->Linkage));
  1390. Status = STATUS_PENDING;
  1391. } else {
  1392. DBGPRINT(IOCTL, ("CheckQueuedNotification: Status Cacelled: IRP=0x%X\n",
  1393. (ULONG_PTR)Irp ));
  1394. TRACE(IOCTL, Irp, pIrpSp, "CheckQueuedNotification.Cancelled:");
  1395. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1396. Status = STATUS_CANCELLED;
  1397. }
  1398. } else {
  1399. Status = STATUS_INSUFFICIENT_RESOURCES;
  1400. }
  1401. *outputBufferLength = 0;
  1402. }
  1403. IoReleaseCancelSpinLock(oldIrql);
  1404. return Status;
  1405. }
  1406. NTSTATUS
  1407. CheckQueuedCompletion(
  1408. IN PQUEUED_COMPLETION pQItem,
  1409. IN PIRP Irp
  1410. )
  1411. /*++
  1412. Routine Description:
  1413. This routine will check for a queued completion structrue
  1414. with the same CfInfoHandle, and it will return it if found.
  1415. The original queued memory block is release here.
  1416. If not found, the returned status is PENDING, o/w the queued status
  1417. is returned.
  1418. Arguments:
  1419. pQItem - pass in the CfInfoHandle and ClientHandle
  1420. Return Value:
  1421. Queued status or STATUS_PENDING
  1422. --*/
  1423. {
  1424. KIRQL oldIrql;
  1425. PLIST_ENTRY pEntry;
  1426. NTSTATUS Status;
  1427. PPENDING_IRP pPendingIrp = NULL;
  1428. PIO_STACK_LOCATION irpStack;
  1429. DBGPRINT(IOCTL, ("CheckQueuedCompletion: pQItem=0x%X\n",
  1430. (ULONG_PTR)pQItem));
  1431. TRACE(IOCTL,
  1432. pQItem->OpCode,
  1433. pQItem->ClientHandle,
  1434. "CheckQueuedCompletion:");
  1435. TRACE(IOCTL,
  1436. pQItem->CfInfoHandle,
  1437. pQItem->Status,
  1438. "CheckQueuedCompletion:");
  1439. IoAcquireCancelSpinLock(&oldIrql);
  1440. for ( pEntry = QueuedCompletionList.Flink;
  1441. pEntry != &QueuedCompletionList;
  1442. pEntry = pEntry->Flink ) {
  1443. pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
  1444. if ((pQItem->OpCode == OP_ANY_CFINFO ||
  1445. pQItem->OpCode == pPendingIrp->QComp.OpCode)
  1446. &&
  1447. pPendingIrp->QComp.ClientHandle == (PVOID)pQItem->ClientHandle
  1448. &&
  1449. pPendingIrp->QComp.CfInfoHandle == (PVOID)pQItem->CfInfoHandle) {
  1450. //
  1451. // the queued item if for this file object
  1452. // and the OpCode match
  1453. // and it has the same CfInfo memory pointer
  1454. //
  1455. GpcRemoveEntryList(pEntry);
  1456. break;
  1457. } else {
  1458. pPendingIrp = NULL;
  1459. }
  1460. }
  1461. if (pPendingIrp) {
  1462. //
  1463. // get the status and free the queued completion item
  1464. //
  1465. DBGPRINT(IOCTL, ("CheckQueuedCompletion: found pPendingIrp=0x%X, Status=0x%X\n",
  1466. (ULONG_PTR)pPendingIrp, pPendingIrp->QComp.Status));
  1467. TRACE(IOCTL,
  1468. pPendingIrp->QComp.OpCode,
  1469. pPendingIrp->QComp.ClientHandle,
  1470. "CheckQueuedCompletion.Q:");
  1471. TRACE(IOCTL,
  1472. pPendingIrp->QComp.CfInfoHandle,
  1473. pPendingIrp->QComp.Status,
  1474. "CheckQueuedCompletion.Q:");
  1475. #if DBG
  1476. if (pQItem->OpCode != OP_ANY_CFINFO) {
  1477. ASSERT(pPendingIrp->QComp.OpCode == pQItem->OpCode);
  1478. ASSERT(pPendingIrp->QComp.ClientHandle == pQItem->ClientHandle);
  1479. }
  1480. #endif
  1481. Status = pPendingIrp->QComp.Status;
  1482. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1483. } else {
  1484. DBGPRINT(IOCTL, ("CheckQueuedCompletion: pPendingIrp not found...PENDING\n"
  1485. ));
  1486. TRACE(IOCTL, 0, 0, "CheckQueuedCompletion.NopQ:");
  1487. GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1488. if (pPendingIrp != NULL) {
  1489. //
  1490. // add the IRP on the pending CfInfo list
  1491. //
  1492. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1493. DBGPRINT(IOCTL, ("CheckQueuedCompletion: adding IRP=0x%X\n",
  1494. (ULONG_PTR)Irp ));
  1495. TRACE(IOCTL, Irp, irpStack, "CheckQueuedCompletion.Irp:");
  1496. pPendingIrp->Irp = Irp;
  1497. pPendingIrp->FileObject = irpStack->FileObject;
  1498. pPendingIrp->QComp.OpCode = pQItem->OpCode;
  1499. pPendingIrp->QComp.ClientHandle = pQItem->ClientHandle;
  1500. pPendingIrp->QComp.CfInfoHandle = pQItem->CfInfoHandle;
  1501. pPendingIrp->QComp.Status = pQItem->Status;
  1502. if (!Irp->Cancel) {
  1503. IoSetCancelRoutine(Irp, CancelPendingIrpCfInfo);
  1504. GpcInsertTailList(&PendingIrpCfInfoList, &(pPendingIrp->Linkage));
  1505. Status = STATUS_PENDING;
  1506. } else {
  1507. DBGPRINT(IOCTL, ("CheckQueuedCompletion: Status Cacelled: IRP=0x%X\n",
  1508. (ULONG_PTR)Irp ));
  1509. TRACE(IOCTL, Irp, irpStack, "CheckQueuedCompletion.Cancelled:");
  1510. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1511. Status = STATUS_CANCELLED;
  1512. }
  1513. } else {
  1514. Status = STATUS_INSUFFICIENT_RESOURCES;
  1515. }
  1516. }
  1517. IoReleaseCancelSpinLock(oldIrql);
  1518. return Status;
  1519. }
  1520. /* end ioctl.c */