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.

3192 lines
91 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. BOOLEAN fNewInterface
  43. );
  44. NTSTATUS
  45. ProxyGpcDeregisterClient(
  46. PVOID ioBuffer,
  47. ULONG inputBufferLength,
  48. ULONG *outputBufferLength,
  49. PFILE_OBJECT FileObject,
  50. BOOLEAN fNewInterface
  51. );
  52. NTSTATUS
  53. ProxyGpcAddCfInfo(
  54. PVOID ioBuffer,
  55. ULONG inputBufferLength,
  56. ULONG *outputBufferLength,
  57. PIRP Irp,
  58. PFILE_OBJECT FileObject
  59. );
  60. NTSTATUS
  61. ProxyGpcAddCfInfoEx(
  62. PVOID ioBuffer,
  63. ULONG inputBufferLength,
  64. ULONG *outputBufferLength,
  65. PIRP Irp,
  66. PFILE_OBJECT FileObject
  67. );
  68. NTSTATUS
  69. ProxyGpcModifyCfInfo(
  70. PVOID ioBuffer,
  71. ULONG inputBufferLength,
  72. ULONG *outputBufferLength,
  73. PIRP Irp,
  74. PFILE_OBJECT FileObject
  75. );
  76. NTSTATUS
  77. ProxyGpcRemoveCfInfo(
  78. PVOID ioBuffer,
  79. ULONG inputBufferLength,
  80. ULONG *outputBufferLength,
  81. PIRP Irp,
  82. PFILE_OBJECT FileObject,
  83. BOOLEAN fNewInterface
  84. );
  85. NTSTATUS
  86. ProxyGpcAddPattern(
  87. PVOID ioBuffer,
  88. ULONG inputBufferLength,
  89. ULONG *outputBufferLength,
  90. PFILE_OBJECT FileObject,
  91. BOOLEAN fNewInterface
  92. );
  93. NTSTATUS
  94. ProxyGpcRemovePattern(
  95. PVOID ioBuffer,
  96. ULONG inputBufferLength,
  97. ULONG *outputBufferLength,
  98. PFILE_OBJECT FileObject,
  99. BOOLEAN fNewInterface
  100. );
  101. NTSTATUS
  102. ProxyGpcEnumCfInfo(
  103. PVOID ioBuffer,
  104. ULONG inputBufferLength,
  105. ULONG *outputBufferLength,
  106. PFILE_OBJECT FileObject
  107. );
  108. NTSTATUS
  109. GpcValidateClientOwner (
  110. IN GPC_HANDLE GpcClientHandle,
  111. IN PFILE_OBJECT pFile
  112. );
  113. NTSTATUS
  114. GpcValidatePatternOwner (
  115. IN GPC_HANDLE GpcClientHandle,
  116. IN GPC_HANDLE GpcPatternHandle
  117. );
  118. NTSTATUS
  119. GpcValidateCfinfoOwner (
  120. IN GPC_HANDLE GpcClientHandle,
  121. IN GPC_HANDLE GpcCfInfoHandle
  122. );
  123. GPC_CLIENT_FUNC_LIST CallBackProxyList;
  124. PDEVICE_OBJECT GPCDeviceObject;
  125. LIST_ENTRY PendingIrpCfInfoList;
  126. LIST_ENTRY PendingIrpNotifyList;
  127. LIST_ENTRY QueuedNotificationList;
  128. LIST_ENTRY QueuedCompletionList;
  129. /* End Forward */
  130. #pragma NDIS_PAGEABLE_FUNCTION(GPCIoctl)
  131. UNICODE_STRING GpcDriverName = {sizeof(DD_GPC_DEVICE_NAME)-2,
  132. sizeof(DD_GPC_DEVICE_NAME),
  133. DD_GPC_DEVICE_NAME};
  134. NTSTATUS
  135. IoctlInitialize(
  136. PDRIVER_OBJECT DriverObject,
  137. PULONG InitShutdownMask
  138. )
  139. /*++
  140. Routine Description:
  141. Perform initialization
  142. Arguments:
  143. DriverObject - pointer to DriverObject from DriverEntry
  144. InitShutdownMask - pointer to mask used to indicate which events have been
  145. successfully init'ed
  146. Return Value:
  147. STATUS_SUCCESS if everything worked ok
  148. --*/
  149. {
  150. NTSTATUS Status;
  151. UINT FuncIndex;
  152. InitializeListHead(&PendingIrpCfInfoList);
  153. InitializeListHead(&PendingIrpNotifyList);
  154. InitializeListHead(&QueuedNotificationList);
  155. InitializeListHead(&QueuedCompletionList);
  156. //
  157. // Initialize the driver object's entry points
  158. //
  159. DriverObject->FastIoDispatch = NULL;
  160. for (FuncIndex = 0; FuncIndex <= IRP_MJ_MAXIMUM_FUNCTION; FuncIndex++) {
  161. DriverObject->MajorFunction[FuncIndex] = GPCIoctl;
  162. }
  163. Status = IoCreateDevice(DriverObject,
  164. 0,
  165. &GpcDriverName,
  166. FILE_DEVICE_NETWORK,
  167. FILE_DEVICE_SECURE_OPEN,
  168. FALSE,
  169. &GPCDeviceObject);
  170. if ( NT_SUCCESS( Status )) {
  171. *InitShutdownMask |= SHUTDOWN_DELETE_DEVICE;
  172. GPCDeviceObject->Flags |= DO_BUFFERED_IO;
  173. /* yoramb - don't need a symbolic link for now...
  174. Status = IoCreateSymbolicLink( &GPCSymbolicName, &GPCDriverName );
  175. if ( NT_SUCCESS( Status )) {
  176. *InitShutdownMask |= SHUTDOWN_DELETE_SYMLINK;
  177. } else {
  178. DBGPRINT(IOCTL, ("IoCreateSymbolicLink Failed (%08X): %ls -> %ls\n",
  179. Status, GPCSymbolicName.Buffer, PSDriverName.Buffer));
  180. }
  181. */
  182. } else {
  183. DbgPrint("IoCreateDevice failed. Status = %x\n", Status);
  184. GPCDeviceObject = NULL;
  185. }
  186. //
  187. // Initialize the callback functions. These are called by the
  188. // kernel Gpc and turned into async notifications to the user.
  189. // For now, the user does not get callbacks, so they are NULL.
  190. //
  191. CallBackProxyList.GpcVersion = GpcMajorVersion;
  192. CallBackProxyList.ClAddCfInfoCompleteHandler = NULL;
  193. CallBackProxyList.ClAddCfInfoNotifyHandler = NULL;
  194. CallBackProxyList.ClModifyCfInfoCompleteHandler = NULL;
  195. CallBackProxyList.ClModifyCfInfoNotifyHandler = NULL;
  196. CallBackProxyList.ClRemoveCfInfoCompleteHandler = NULL;
  197. CallBackProxyList.ClRemoveCfInfoNotifyHandler = NULL;
  198. return Status;
  199. }
  200. NTSTATUS
  201. GPCIoctl(
  202. IN PDEVICE_OBJECT DeviceObject,
  203. IN PIRP Irp
  204. )
  205. /*++
  206. Routine Description:
  207. Process the IRPs sent to this device.
  208. Arguments:
  209. DeviceObject - pointer to a device object
  210. Irp - pointer to an I/O Request Packet
  211. Return Value:
  212. None
  213. --*/
  214. {
  215. PIO_STACK_LOCATION irpStack;
  216. PVOID ioBuffer;
  217. ULONG inputBufferLength;
  218. ULONG outputBufferLength;
  219. ULONG ioControlCode;
  220. UCHAR saveControlFlags;
  221. NTSTATUS Status = STATUS_SUCCESS;
  222. #if DBG
  223. KIRQL irql = KeGetCurrentIrql();
  224. KIRQL irql2;
  225. HANDLE thrd = PsGetCurrentThreadId();
  226. #endif
  227. PAGED_CODE();
  228. //
  229. // Init to default settings- we only expect 1 type of
  230. // IOCTL to roll through here, all others an error.
  231. //
  232. Irp->IoStatus.Status = STATUS_SUCCESS;
  233. Irp->IoStatus.Information = 0;
  234. //
  235. // Get a pointer to the current location in the Irp. This is where
  236. // the function codes and parameters are located.
  237. //
  238. irpStack = IoGetCurrentIrpStackLocation(Irp);
  239. //
  240. // Get the pointer to the input/output buffer and it's length
  241. //
  242. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  243. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  244. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  245. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  246. saveControlFlags = irpStack->Control;
  247. TRACE(LOCKS, thrd, irql, "GPCIoctl");
  248. switch (irpStack->MajorFunction) {
  249. case IRP_MJ_CREATE:
  250. DBGPRINT(IOCTL, ("IRP Create\n"));
  251. break;
  252. case IRP_MJ_READ:
  253. DBGPRINT(IOCTL, ("IRP Read\n"));
  254. break;
  255. case IRP_MJ_CLOSE:
  256. DBGPRINT(IOCTL, ("IRP Close\n"));
  257. TRACE(IOCTL, irpStack->FileObject, 0, "IRP Close");
  258. //
  259. // make sure we clean all the objects for this particular
  260. // file object, since it's closing right now.
  261. //
  262. CloseAllObjects(irpStack->FileObject, Irp);
  263. break;
  264. case IRP_MJ_CLEANUP:
  265. DBGPRINT(IOCTL, ("IRP Cleanup\n"));
  266. break;
  267. case IRP_MJ_SHUTDOWN:
  268. DBGPRINT(IOCTL, ("IRP Shutdown\n"));
  269. break;
  270. case IRP_MJ_DEVICE_CONTROL:
  271. DBGPRINT(IOCTL, ("GPCIoctl: ioctl=0x%X, IRP=0x%X\n",
  272. ioControlCode, (ULONG_PTR)Irp));
  273. TRACE(IOCTL, ioControlCode, Irp, "GPCIoctl.irp:");
  274. //
  275. // Mark the IRP as Pending BEFORE calling any dispatch routine.
  276. // If Status is actually set to STATUS_PENDING, we assume the IRP
  277. // is ready to be returned.
  278. // It is possible the IoCompleteRequest has been called async for the
  279. // IRP, but this should be taken care of by the IO subsystem.
  280. //
  281. IoMarkIrpPending(Irp);
  282. switch (ioControlCode) {
  283. case IOCTL_GPC_REGISTER_CLIENT:
  284. Status = ProxyGpcRegisterClient(ioBuffer,
  285. inputBufferLength,
  286. &outputBufferLength,
  287. irpStack->FileObject,
  288. FALSE); //Admin Only
  289. break;
  290. case IOCTL_GPC_REGISTER_CLIENT_EX:
  291. Status = ProxyGpcRegisterClient(ioBuffer,
  292. inputBufferLength,
  293. &outputBufferLength,
  294. irpStack->FileObject,
  295. TRUE); // All users
  296. break;
  297. case IOCTL_GPC_DEREGISTER_CLIENT:
  298. Status = ProxyGpcDeregisterClient(ioBuffer,
  299. inputBufferLength,
  300. &outputBufferLength,
  301. irpStack->FileObject,
  302. FALSE
  303. );// Admin Only Call
  304. break;
  305. case IOCTL_GPC_DEREGISTER_CLIENT_EX:
  306. Status = ProxyGpcDeregisterClient(ioBuffer,
  307. inputBufferLength,
  308. &outputBufferLength,
  309. irpStack->FileObject,
  310. TRUE);// All users
  311. break;
  312. case IOCTL_GPC_ADD_CF_INFO:
  313. Status = ProxyGpcAddCfInfo(ioBuffer,
  314. inputBufferLength,
  315. &outputBufferLength,
  316. Irp,
  317. irpStack->FileObject
  318. );
  319. break;
  320. // RSVP Removal Change
  321. // New IOCTL added
  322. case IOCTL_GPC_ADD_CF_INFO_EX:
  323. Status = ProxyGpcAddCfInfoEx(ioBuffer,
  324. inputBufferLength,
  325. &outputBufferLength,
  326. Irp,
  327. irpStack->FileObject
  328. );
  329. break;
  330. case IOCTL_GPC_MODIFY_CF_INFO:
  331. Status = ProxyGpcModifyCfInfo(ioBuffer,
  332. inputBufferLength,
  333. &outputBufferLength,
  334. Irp,
  335. irpStack->FileObject
  336. );
  337. break;
  338. case IOCTL_GPC_REMOVE_CF_INFO:
  339. Status = ProxyGpcRemoveCfInfo(ioBuffer,
  340. inputBufferLength,
  341. &outputBufferLength,
  342. Irp,
  343. irpStack->FileObject,
  344. FALSE);//Admin Only
  345. break;
  346. case IOCTL_GPC_REMOVE_CF_INFO_EX:
  347. Status = ProxyGpcRemoveCfInfo(ioBuffer,
  348. inputBufferLength,
  349. &outputBufferLength,
  350. Irp,
  351. irpStack->FileObject,
  352. TRUE);//All User
  353. break;
  354. case IOCTL_GPC_ADD_PATTERN:
  355. Status = ProxyGpcAddPattern(ioBuffer,
  356. inputBufferLength,
  357. &outputBufferLength,
  358. irpStack->FileObject,
  359. FALSE); //Admin only IOCTL
  360. break;
  361. case IOCTL_GPC_ADD_PATTERN_EX:
  362. Status = ProxyGpcAddPattern(ioBuffer,
  363. inputBufferLength,
  364. &outputBufferLength,
  365. irpStack->FileObject,
  366. TRUE); // All user IOCTL
  367. break;
  368. case IOCTL_GPC_REMOVE_PATTERN:
  369. Status = ProxyGpcRemovePattern(ioBuffer,
  370. inputBufferLength,
  371. &outputBufferLength,
  372. irpStack->FileObject,
  373. FALSE);// Admin Only IOCTL
  374. break;
  375. case IOCTL_GPC_REMOVE_PATTERN_EX:
  376. Status = ProxyGpcRemovePattern(ioBuffer,
  377. inputBufferLength,
  378. &outputBufferLength,
  379. irpStack->FileObject,
  380. TRUE);// All user IOCTL
  381. break;
  382. case IOCTL_GPC_ENUM_CFINFO:
  383. Status = ProxyGpcEnumCfInfo(ioBuffer,
  384. inputBufferLength,
  385. &outputBufferLength,
  386. irpStack->FileObject);
  387. break;
  388. case IOCTL_GPC_NOTIFY_REQUEST:
  389. //
  390. // request to pend an IRP
  391. //
  392. Status = CheckQueuedNotification(Irp, &outputBufferLength);
  393. break;
  394. case IOCTL_GPC_GET_ENTRIES:
  395. // Locking Down Kmode Only IOCTLs
  396. if (ExGetPreviousMode() != KernelMode)
  397. {
  398. Status = STATUS_ACCESS_DENIED;
  399. break;
  400. }
  401. #ifdef STANDALONE_DRIVER
  402. //
  403. // Return the exported calls in the buffer
  404. //
  405. if (outputBufferLength >= sizeof(glGpcExportedCalls)) {
  406. NdisMoveMemory(ioBuffer,
  407. &glGpcExportedCalls,
  408. sizeof(glGpcExportedCalls));
  409. outputBufferLength = sizeof(glGpcExportedCalls);
  410. } else {
  411. outputBufferLength = sizeof(glGpcExportedCalls);
  412. Status = GPC_STATUS_INSUFFICIENT_BUFFER;
  413. }
  414. #else
  415. Status = STATUS_INVALID_PARAMETER;
  416. #endif
  417. break;
  418. default:
  419. DBGPRINT(IOCTL, ("GPCIoctl: Unknown IRP_MJ_DEVICE_CONTROL\n = %X\n",
  420. ioControlCode));
  421. Status = STATUS_INVALID_PARAMETER;
  422. break;
  423. } // switch (ioControlCode)
  424. break;
  425. default:
  426. DBGPRINT(IOCTL, ("GPCIoctl: Unknown IRP major function = %08X\n",
  427. irpStack->MajorFunction));
  428. Status = STATUS_UNSUCCESSFUL;
  429. break;
  430. }
  431. DBGPRINT(IOCTL, ("GPCIoctl: Status=0x%X, IRP=0x%X, outSize=%d\n",
  432. Status, (ULONG_PTR)Irp, outputBufferLength));
  433. TRACE(IOCTL, Irp, Status, "GPCIoctl.Complete:");
  434. if (Status != STATUS_PENDING) {
  435. //
  436. // IRP completed and it's not Pending, we need to restore the Control flags,
  437. // since it might have been marked as Pending before...
  438. //
  439. irpStack->Control = saveControlFlags;
  440. Irp->IoStatus.Status = Status;
  441. Irp->IoStatus.Information = outputBufferLength;
  442. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  443. }
  444. #if DBG
  445. irql2 = KeGetCurrentIrql();
  446. ASSERT(irql == irql2);
  447. #endif
  448. TRACE(LOCKS, thrd, irql2, "GPCIoctl (end)");
  449. return Status;
  450. } // GPCIoctl
  451. VOID
  452. IoctlCleanup(
  453. ULONG ShutdownMask
  454. )
  455. /*++
  456. Routine Description:
  457. Cleanup code for Initialize
  458. Arguments:
  459. ShutdownMask - mask indicating which functions need to be cleaned up
  460. Return Value:
  461. None
  462. --*/
  463. {
  464. /*
  465. if ( ShutdownMask & SHUTDOWN_DELETE_SYMLINK ) {
  466. IoDeleteSymbolicLink( &PSSymbolicName );
  467. }
  468. */
  469. if ( ShutdownMask & SHUTDOWN_DELETE_DEVICE ) {
  470. IoDeleteDevice( GPCDeviceObject );
  471. }
  472. }
  473. NTSTATUS
  474. TcpQueryInfoComplete(PDEVICE_OBJECT pDeviceObject,
  475. PIRP Irp,
  476. PVOID Context)
  477. {
  478. PTDI_ROUTING_INFO RoutingInfo;
  479. PTRANSPORT_ADDRESS TransportAddress;
  480. PTA_ADDRESS TaAddress;
  481. PTDI_ADDRESS_IP IpAddress;
  482. int i;
  483. PGPC_IP_PATTERN pTcpPattern;
  484. PGPC_TCP_QUERY_CONTEXT pGpcTcpContext;
  485. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  486. RoutingInfo = (PTDI_ROUTING_INFO)Context;
  487. //
  488. // Get a pointer to the Original Context. This allows us to access the GPC_IP_PATTERN
  489. pGpcTcpContext = CONTAINING_RECORD(Context,GPC_TCP_QUERY_CONTEXT,RouteInfo);
  490. //
  491. // Retreive the pointer to the GPC_IP_PATTERN
  492. pTcpPattern = pGpcTcpContext->pTcpPattern;
  493. // Check status .
  494. if (Irp->IoStatus.Status != STATUS_SUCCESS){
  495. goto exit;
  496. }
  497. DBGPRINT(IOCTL,("\n"));
  498. DBGPRINT(IOCTL,("Protocol: %d\n", RoutingInfo->Protocol));
  499. DBGPRINT(IOCTL,("InterfaceId: %d\n", RoutingInfo->InterfaceId));
  500. DBGPRINT(IOCTL,("LinkId: %d\n", RoutingInfo->LinkId));
  501. // Fill up the values of the Interface
  502. pTcpPattern->InterfaceId.InterfaceId = RoutingInfo->InterfaceId;
  503. pTcpPattern->InterfaceId.LinkId = RoutingInfo->LinkId;
  504. TransportAddress = (PTRANSPORT_ADDRESS)&RoutingInfo->Address;
  505. DBGPRINT(IOCTL,("Address Count: %d\n",TransportAddress->TAAddressCount));
  506. TaAddress = (PTA_ADDRESS)&TransportAddress->Address;
  507. if ((2 < TransportAddress->TAAddressCount) || (1 > TransportAddress->TAAddressCount)){
  508. // Release Memory
  509. Status = STATUS_MORE_PROCESSING_REQUIRED;
  510. ASSERT(FALSE);
  511. goto exit;
  512. }
  513. IpAddress = (PTDI_ADDRESS_IP)&TaAddress->Address;
  514. pTcpPattern->SrcAddr = IpAddress->in_addr;
  515. pTcpPattern->gpcSrcPort = IpAddress->sin_port;
  516. DBGPRINT(IOCTL,("AddressLength = %d\n",TaAddress->AddressLength));
  517. DBGPRINT(IOCTL,("AddressType = %d\n",TaAddress->AddressType));
  518. DBGPRINT(IOCTL,("Port = %d\n",IpAddress->sin_port));
  519. DBGPRINT(IOCTL,("Address = %d.%d.%d.%d\n",
  520. (IpAddress->in_addr & 0xff000000) >> 24,
  521. (IpAddress->in_addr & 0x00ff0000) >> 16,
  522. (IpAddress->in_addr & 0x0000ff00) >> 8,
  523. IpAddress->in_addr & 0x000000ff));
  524. if ( 2 == TransportAddress->TAAddressCount)
  525. {
  526. TaAddress = (PTA_ADDRESS)((PUCHAR)TaAddress +
  527. FIELD_OFFSET(TA_ADDRESS, Address) +
  528. TaAddress->AddressLength);
  529. IpAddress = (PTDI_ADDRESS_IP)&TaAddress->Address;
  530. pTcpPattern->DstAddr = IpAddress->in_addr;
  531. pTcpPattern->gpcDstPort = IpAddress->sin_port;
  532. pTcpPattern->ProtocolId = IPPROTO_TCP;
  533. DBGPRINT(IOCTL,("AddressLength = %d\n",TaAddress->AddressLength));
  534. DBGPRINT(IOCTL,("AddressType = %d\n",TaAddress->AddressType));
  535. DBGPRINT(IOCTL,("Port = %d\n",IpAddress->sin_port));
  536. DBGPRINT(IOCTL,("Address = %d.%d.%d.%d\n",
  537. (IpAddress->in_addr & 0xff000000) >> 24,
  538. (IpAddress->in_addr & 0x00ff0000) >> 16,
  539. (IpAddress->in_addr & 0x0000ff00) >> 8,
  540. IpAddress->in_addr & 0x000000ff));
  541. }
  542. else{
  543. pTcpPattern->ProtocolId = IPPROTO_UDP;
  544. }
  545. //
  546. // Need to free the Memory allocated, MDL and the IRP here.
  547. exit:
  548. IoFreeMdl(pGpcTcpContext->pMdl);
  549. GpcFreeMem(pGpcTcpContext,TcpQueryContextTag);
  550. IoFreeIrp(Irp);
  551. return Status;
  552. }
  553. void
  554. BuildTDIAddress(uchar * Buffer, IPAddr Addr, ushort Port)
  555. {
  556. PTRANSPORT_ADDRESS XportAddr;
  557. PTA_ADDRESS TAAddr;
  558. XportAddr = (PTRANSPORT_ADDRESS) Buffer;
  559. XportAddr->TAAddressCount = 1;
  560. TAAddr = XportAddr->Address;
  561. TAAddr->AddressType = TDI_ADDRESS_TYPE_IP;
  562. TAAddr->AddressLength = sizeof(TDI_ADDRESS_IP);
  563. ((PTDI_ADDRESS_IP) TAAddr->Address)->sin_port = Port;
  564. ((PTDI_ADDRESS_IP) TAAddr->Address)->in_addr = Addr;
  565. memset(((PTDI_ADDRESS_IP) TAAddr->Address)->sin_zero,
  566. 0,
  567. sizeof(((PTDI_ADDRESS_IP) TAAddr->Address)->sin_zero));
  568. }
  569. NTSTATUS
  570. TcpQueryInfo(PFILE_OBJECT FileObject, PGPC_IP_PATTERN pTcpPattern, ULONG RemoteAddress, USHORT RemotePort)
  571. {
  572. PIRP pIrp = NULL;
  573. PMDL pMdl = NULL;
  574. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  575. PVOID pBuffer = NULL;
  576. PVOID pInputBuf = NULL;
  577. PIO_STACK_LOCATION pIrpSp;
  578. TDI_CONNECTION_INFORMATION ConnInfo;
  579. UCHAR InputBuf[FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
  580. FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP)];
  581. PTRANSPORT_ADDRESS Address1;
  582. PTA_ADDRESS Address2;
  583. PGPC_IP_PATTERN * ppPattern;
  584. PGPC_TCP_QUERY_CONTEXT pContext= NULL;
  585. // IRP for querying TCPIP
  586. //Charge quota for outstanding IRPs
  587. try{
  588. pIrp = IoAllocateIrp((CCHAR)(FileObject->DeviceObject->StackSize), TRUE);
  589. }
  590. except(EXCEPTION_EXECUTE_HANDLER){
  591. pIrp = NULL;
  592. }
  593. //Check for allocation failure
  594. if (pIrp == NULL){
  595. Status = STATUS_INSUFFICIENT_RESOURCES;
  596. goto exit;
  597. }
  598. //
  599. // Build output buf
  600. // Allocate Space for GPC_TCP_QUERY_CONTEXT
  601. //
  602. GpcAllocMemWithQuota(&pBuffer, ROUTING_INFO_ADDR_2_SIZE, TcpQueryContextTag);
  603. // Check for allocation failure
  604. if (pBuffer==NULL) {
  605. Status = GPC_STATUS_RESOURCES ;
  606. goto exit;
  607. }
  608. // Will use pContext to index into the Data Structure
  609. pContext = (PGPC_TCP_QUERY_CONTEXT)pBuffer;
  610. // Store our pointer to Pattern at the beginning of the Buffer
  611. (pContext->pTcpPattern) = pTcpPattern;
  612. // Initialize with Remote Ports
  613. // Will disregard these values if we get back 2 addresses from TCP
  614. pTcpPattern->DstAddr = RemoteAddress;
  615. pTcpPattern->gpcDstPort = RemotePort;
  616. // Jump over the pointer stored
  617. pBuffer = &(pContext->RouteInfo);
  618. // Charge Quota for the MDL allocation
  619. try{
  620. pMdl = IoAllocateMdl(pBuffer, ROUTING_INFO_ADDR_2_SIZE-
  621. FIELD_OFFSET(GPC_TCP_QUERY_CONTEXT ,RouteInfo), FALSE, TRUE, NULL);
  622. }
  623. except(EXCEPTION_EXECUTE_HANDLER){
  624. pMdl = NULL;
  625. }
  626. //Check for allocation failure
  627. if (pMdl==NULL) {
  628. Status = GPC_STATUS_RESOURCES;
  629. goto exit;
  630. }
  631. // Should not Fail
  632. MmBuildMdlForNonPagedPool(pMdl);
  633. // Store our pointer to MDL in the context
  634. pContext->pMdl = pMdl;
  635. //
  636. // Build the input buf
  637. // Not Expected to Fail
  638. BuildTDIAddress(InputBuf, RemoteAddress, RemotePort);
  639. ConnInfo.RemoteAddress = InputBuf;
  640. ConnInfo.RemoteAddressLength = 100;
  641. // Should not Fail
  642. TdiBuildQueryInformationEx(pIrp,
  643. FileObject->DeviceObject,
  644. FileObject,
  645. (PIO_COMPLETION_ROUTINE)TcpQueryInfoComplete,
  646. pBuffer, // Context in completion call
  647. TDI_QUERY_ROUTING_INFO,
  648. pMdl,
  649. &ConnInfo);
  650. // Completion handler always called, don't care on return value.
  651. Status=IoCallDriver(FileObject->DeviceObject, pIrp);
  652. // Per SanjayKa the call should always completely syncrhonously
  653. // If we made the call memory would be released in our
  654. // completion function
  655. return Status;
  656. exit:
  657. // release all memory
  658. //allocated before returning
  659. // if we failed at some
  660. // stage
  661. if (pMdl){
  662. IoFreeMdl(pMdl);
  663. }
  664. if (pContext){
  665. GpcFreeMem(pContext,TcpQueryContextTag);
  666. }
  667. if (pIrp){
  668. IoFreeIrp(pIrp);
  669. }
  670. return Status;
  671. }
  672. // Function: ProxyGpcRegisterClient
  673. //
  674. // Parameters:
  675. // PVOID ioBuffer: The buffer containing request and result
  676. // ULONG inputBufferLength: Size of Request
  677. // ULONG * outputBufferLength: Size of Result
  678. // PFILE_OBJECT: The client's file object
  679. //
  680. // Result: The Status of the Call. an fail the IRP or return failure in the
  681. // GPC result structure
  682. // Environment:
  683. // For use with the new REGISTER_CLIENT and REGISTER_CLIENT_EX
  684. // Ioctls
  685. NTSTATUS
  686. ProxyGpcRegisterClient(
  687. PVOID ioBuffer,
  688. ULONG inputBufferLength,
  689. ULONG *outputBufferLength,
  690. PFILE_OBJECT FileObject,
  691. BOOLEAN fNewInterface
  692. )
  693. {
  694. NTSTATUS Status;
  695. PCLIENT_BLOCK pClient;
  696. PGPC_REGISTER_CLIENT_REQ GpcReq;
  697. PGPC_REGISTER_CLIENT_RES GpcRes;
  698. if (inputBufferLength < sizeof(GPC_REGISTER_CLIENT_REQ)
  699. ||
  700. *outputBufferLength < sizeof(GPC_REGISTER_CLIENT_RES)
  701. ) {
  702. return STATUS_BUFFER_TOO_SMALL;
  703. }
  704. if (fNewInterface){
  705. // Do not allow HTTP to use this IOCTL interface
  706. //
  707. if ( KernelMode == ExGetPreviousMode() ){
  708. return GPC_STATUS_NOT_SUPPORTED;
  709. }
  710. }
  711. GpcReq = (PGPC_REGISTER_CLIENT_REQ)ioBuffer;
  712. GpcRes = (PGPC_REGISTER_CLIENT_RES)ioBuffer;
  713. // Old IOCTL interface locked down to QOS only
  714. if (GpcReq->CfId != GPC_CF_QOS) return GPC_STATUS_INVALID_PARAMETER;
  715. // Check the flags the user is allowed to pass in
  716. if (!((GpcReq->Flags == 0) ||(GpcReq->Flags == GPC_FLAGS_FRAGMENT))){
  717. return GPC_STATUS_INVALID_PARAMETER;
  718. }
  719. // Check the number of priorities requested
  720. if (GpcReq->MaxPriorities > GPC_PRIORITY_MAX) {
  721. return GPC_STATUS_INVALID_PARAMETER;
  722. }
  723. // ClientContext not validated since we dont do anything
  724. // with it except return it to the client
  725. if (fNewInterface){
  726. Status = GpcRegisterClient(GpcReq->CfId,
  727. GpcReq->Flags | GPC_FLAGS_USERMODE_CLIENT
  728. |GPC_FLAGS_USERMODE_CLIENT_EX,
  729. GpcReq->MaxPriorities,
  730. &CallBackProxyList,
  731. GpcReq->ClientContext,
  732. (PGPC_HANDLE)&pClient);
  733. }
  734. else{
  735. Status = GpcRegisterClient(GpcReq->CfId,
  736. GpcReq->Flags | GPC_FLAGS_USERMODE_CLIENT,
  737. GpcReq->MaxPriorities,
  738. &CallBackProxyList,
  739. GpcReq->ClientContext,
  740. (PGPC_HANDLE)&pClient);
  741. }
  742. ASSERT(Status != GPC_STATUS_PENDING);
  743. if (Status == STATUS_SUCCESS) {
  744. ASSERT(pClient);
  745. pClient->pFileObject = FileObject;
  746. GpcRes->ClientHandle = AllocateHandle(&pClient->ClHandle, (PVOID)pClient);
  747. if (GpcRes->ClientHandle == NULL)
  748. {
  749. //Got a NULL Handle release the CLIENT_BLOCK
  750. GpcDeregisterClient(pClient);
  751. Status = GPC_STATUS_RESOURCES;
  752. }
  753. }
  754. GpcRes->Status = Status;
  755. *outputBufferLength = sizeof(GPC_REGISTER_CLIENT_RES);
  756. return STATUS_SUCCESS;
  757. }
  758. // Function: ProxyGpcDeregisterClientEx
  759. //
  760. // Parameters:
  761. // PVOID ioBuffer: The buffer containing request and result
  762. // ULONG inputBufferLength: Size of Request
  763. // ULONG * outputBufferLength: Size of Result
  764. // PFILE_OBJECT: The client's file object
  765. //
  766. // Result: The Status of the Call. can fail the IRP or return failure in the
  767. // GPC result structure
  768. // Environment:
  769. // For use with the new DEREGISTER_CLIENT_EX and DEREGISTER_CLIENT
  770. // ioctls
  771. NTSTATUS
  772. ProxyGpcDeregisterClient(
  773. PVOID ioBuffer,
  774. ULONG inputBufferLength,
  775. ULONG *outputBufferLength,
  776. PFILE_OBJECT FileObject,
  777. BOOLEAN fNewInterface
  778. )
  779. {
  780. NTSTATUS Status;
  781. PGPC_DEREGISTER_CLIENT_REQ GpcReq;
  782. PGPC_DEREGISTER_CLIENT_RES GpcRes;
  783. GPC_HANDLE GpcClientHandle;
  784. if (inputBufferLength < sizeof(GPC_DEREGISTER_CLIENT_REQ)
  785. ||
  786. *outputBufferLength < sizeof(GPC_DEREGISTER_CLIENT_RES)
  787. ) {
  788. return STATUS_BUFFER_TOO_SMALL;
  789. }
  790. if (fNewInterface){
  791. // Do not allow HTTP to use this IOCTL interface
  792. //
  793. if ( KernelMode == ExGetPreviousMode() ){
  794. return GPC_STATUS_NOT_SUPPORTED;
  795. }
  796. }
  797. GpcReq = (PGPC_DEREGISTER_CLIENT_REQ)ioBuffer;
  798. GpcRes = (PGPC_DEREGISTER_CLIENT_RES)ioBuffer;
  799. //Validate that the client handle maps on to a CLIENT_BLOCK
  800. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  801. GPC_ENUM_CLIENT_TYPE,
  802. 'PGDC');
  803. if (!GpcClientHandle) {
  804. Status = GPC_STATUS_INVALID_HANDLE;
  805. goto exit;
  806. }
  807. //
  808. // Validate that the client handle is owned by the
  809. // calling user mode app.
  810. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  811. if (STATUS_SUCCESS != Status){
  812. goto exit;
  813. }
  814. Status = GpcDeregisterClient(GpcClientHandle);
  815. exit:
  816. if (GpcClientHandle) {
  817. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGDC');
  818. }
  819. ASSERT(Status != GPC_STATUS_PENDING);
  820. GpcRes->Status = Status;
  821. *outputBufferLength = sizeof(GPC_DEREGISTER_CLIENT_RES);
  822. return STATUS_SUCCESS;
  823. }
  824. //
  825. // Function for Handling New IOCTL
  826. // for adding cfinfo now open
  827. // to all users.
  828. //
  829. // Function: ProxyGpcAddCfInfoEx
  830. //
  831. // Parameters:
  832. // PVOID ioBuffer: The buffer containing request and result
  833. // ULONG inputBufferLength: Size of Request
  834. // ULONG * outputBufferLength: Size of Result
  835. // PIRP Irp: The Irp
  836. //
  837. // Result: The Status of the Call. One of GPC_STATUS_VALUES
  838. // documented in gpcifc.h
  839. // Environment:
  840. // To be used in response tos calls from winsock helper dll
  841. // for installing QOS flows for TCP sockets.
  842. NTSTATUS
  843. ProxyGpcAddCfInfoEx(
  844. PVOID ioBuffer,
  845. ULONG inputBufferLength,
  846. ULONG *outputBufferLength,
  847. PIRP Irp,
  848. PFILE_OBJECT FileObject
  849. )
  850. {
  851. NTSTATUS Status;
  852. GPC_HANDLE GpcClientHandle = NULL;
  853. PGPC_ADD_CF_INFO_EX_REQ GpcReq = NULL;
  854. PGPC_ADD_CF_INFO_RES GpcRes = NULL;
  855. PBLOB_BLOCK pBlob = NULL;
  856. QUEUED_COMPLETION QItem;
  857. UNICODE_STRING CfInfoName;
  858. USHORT NameLen = 0;
  859. PGPC_IP_PATTERN pTcpPattern = NULL;
  860. if (inputBufferLength < sizeof(GPC_ADD_CF_INFO_EX_REQ)
  861. ||
  862. *outputBufferLength < sizeof(GPC_ADD_CF_INFO_RES)
  863. ) {
  864. return STATUS_BUFFER_TOO_SMALL;
  865. }
  866. // Do not allow HTTP to use this IOCTL interface
  867. //
  868. if ( KernelMode == ExGetPreviousMode() )
  869. {
  870. return GPC_STATUS_NOT_SUPPORTED;
  871. }
  872. GpcReq = (PGPC_ADD_CF_INFO_EX_REQ)ioBuffer;
  873. GpcRes = (PGPC_ADD_CF_INFO_RES)ioBuffer;
  874. // Validating CfInfo and CfInfoSize
  875. if (GpcReq->CfInfoSize >
  876. inputBufferLength - FIELD_OFFSET(GPC_ADD_CF_INFO_EX_REQ, CfInfo)) {
  877. return STATUS_INVALID_BUFFER_SIZE;
  878. }
  879. // Should be atleast 1 byte : minimum size of variable length array
  880. if (GpcReq->CfInfoSize < sizeof(CHAR)) return GPC_STATUS_INVALID_PARAMETER;
  881. // NULL Handle
  882. if (NULL == GpcReq->FileHandle) return GPC_STATUS_INVALID_HANDLE;
  883. // Validate that the client handle maps on to a CLIENT_BLOCK
  884. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  885. GPC_ENUM_CLIENT_TYPE,
  886. 'PGAC');
  887. //Failed to get the client handle
  888. if (!GpcClientHandle){
  889. Status = GPC_STATUS_INVALID_HANDLE;
  890. goto exit;
  891. }
  892. //
  893. // Validate that the client handle is owned by the
  894. // calling user mode app.
  895. //
  896. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  897. if (Status != GPC_STATUS_SUCCESS) {
  898. // Need to release reference to CLIENT_BLOCK acquired earlier
  899. //
  900. goto exit;
  901. }
  902. // This is the new functionality
  903. // Validate who owns the socket.
  904. // Get the fully specified pattern from TCP
  905. // Let's validate the request: file-object must be present
  906. //
  907. // 1. Get the file object for the file handle
  908. Status = ObReferenceObjectByHandle(GpcReq->FileHandle,
  909. 0,
  910. NULL,
  911. KernelMode,
  912. &FileObject,
  913. NULL);
  914. if (Status != GPC_STATUS_SUCCESS) {
  915. goto exit;
  916. }
  917. GpcAllocMemWithQuota(&pTcpPattern , sizeof(GPC_IP_PATTERN), TcpPatternTag);
  918. if (pTcpPattern == NULL) {
  919. goto exit;
  920. }
  921. // The IOCTL sent by this function completes synchronously
  922. // Expect the GPC_IP_PATTERN in pTcpPattern
  923. //
  924. Status = TcpQueryInfo(FileObject, pTcpPattern,GpcReq->RemoteAddress,GpcReq->RemotePort);
  925. if (STATUS_SUCCESS != Status)
  926. goto exit;
  927. Status = privateGpcAddCfInfo(GpcClientHandle,
  928. GpcReq->CfInfoSize,
  929. &GpcReq->CfInfo,
  930. GpcReq->ClientCfInfoContext,
  931. FileObject,
  932. pTcpPattern,
  933. (PGPC_HANDLE)&pBlob);
  934. if (NT_SUCCESS(Status)) {
  935. //
  936. // including PENDING
  937. //
  938. if (Status == GPC_STATUS_PENDING) {
  939. QItem.OpCode = OP_ADD_CFINFO;
  940. QItem.ClientHandle = GpcClientHandle;
  941. QItem.CfInfoHandle = (GPC_HANDLE)pBlob;
  942. Status = CheckQueuedCompletion(&QItem, Irp);
  943. }
  944. if (Status == GPC_STATUS_SUCCESS) {
  945. GPC_STATUS st = GPC_STATUS_FAILURE;
  946. GPC_CLIENT_HANDLE NotifiedClientCtx = pBlob->NotifiedClientCtx;
  947. PCLIENT_BLOCK pNotifiedClient = pBlob->pNotifiedClient;
  948. GpcRes->GpcCfInfoHandle = (GPC_HANDLE)AllocateHandle(&pBlob->ClHandle, (PVOID)pBlob);
  949. // what if we cant allocate a handle? fail the add!
  950. if (!GpcRes->GpcCfInfoHandle) {
  951. GpcRemoveCfInfo(GpcClientHandle,
  952. pBlob);
  953. Status = GPC_STATUS_RESOURCES;
  954. // This memory is freed in
  955. // GpcRemoveCfInfo
  956. // due to dereferencing that blob
  957. pTcpPattern = NULL;
  958. goto exit;
  959. }
  960. if (pNotifiedClient) {
  961. if (pNotifiedClient->FuncList.ClGetCfInfoName &&
  962. NotifiedClientCtx) {
  963. st = pNotifiedClient->FuncList.ClGetCfInfoName(
  964. pNotifiedClient->ClientCtx,
  965. NotifiedClientCtx,
  966. &CfInfoName
  967. );
  968. if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
  969. CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
  970. //
  971. // RajeshSu claims this can never happen.
  972. //
  973. ASSERT(NT_SUCCESS(st));
  974. }
  975. }
  976. if (NT_SUCCESS(st)) {
  977. //
  978. // copy the instance name
  979. //
  980. GpcRes->InstanceNameLength = NameLen = CfInfoName.Length;
  981. RtlMoveMemory(GpcRes->InstanceName,
  982. CfInfoName.Buffer,
  983. CfInfoName.Length
  984. );
  985. } else {
  986. //
  987. // generate a default name
  988. //
  989. if (NotifiedClientCtx)
  990. swprintf(GpcRes->InstanceName, L"Flow %08X", NotifiedClientCtx);
  991. else
  992. swprintf(GpcRes->InstanceName, L"Flow <unkonwn name>");
  993. GpcRes->InstanceNameLength = NameLen = wcslen(GpcRes->InstanceName)*sizeof(WCHAR);
  994. }
  995. GpcRes->InstanceName[GpcRes->InstanceNameLength/sizeof(WCHAR)] = L'\0';
  996. } else {
  997. pBlob = NULL;
  998. // The pattern is freed along with the blob
  999. // We have a guarantee that it was at least
  1000. // associated with the blob synchronously
  1001. pTcpPattern = NULL;
  1002. }
  1003. }
  1004. else
  1005. {
  1006. // This memory is freed in
  1007. // PrivateGpcAddCfInfoEx
  1008. // if that function fails
  1009. pTcpPattern = NULL;
  1010. }
  1011. //
  1012. // release the ref count we got earlier
  1013. //
  1014. exit:
  1015. if (GpcClientHandle) {
  1016. //
  1017. // release the ref count we got earlier
  1018. //
  1019. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAC');
  1020. }
  1021. if (!NT_SUCCESS(Status) && (pTcpPattern)){
  1022. GpcFreeMem(pTcpPattern, TcpPatternTag);
  1023. }
  1024. GpcRes->InstanceNameLength = NameLen;
  1025. GpcRes->Status = Status;
  1026. *outputBufferLength = sizeof(GPC_ADD_CF_INFO_RES);
  1027. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  1028. }
  1029. // Function: ProxyGpcAddCfInfo
  1030. //
  1031. // Parameters:
  1032. // PVOID ioBuffer: The buffer containing request and result
  1033. // ULONG inputBufferLength: Size of Request
  1034. // ULONG * outputBufferLength: Size of Result
  1035. // PIRP Irp: The Irp
  1036. //
  1037. // Result: The Status of the Call. One of GPC_STATUS_VALUES
  1038. // documented in gpcifc.h
  1039. // Environment:
  1040. // To be used in response to calls from HTTP.sys and traffic.dll
  1041. // for installing QOS flows for TCP sockets.
  1042. NTSTATUS
  1043. ProxyGpcAddCfInfo(
  1044. PVOID ioBuffer,
  1045. ULONG inputBufferLength,
  1046. ULONG *outputBufferLength,
  1047. PIRP Irp,
  1048. PFILE_OBJECT FileObject
  1049. )
  1050. {
  1051. NTSTATUS Status;
  1052. GPC_HANDLE GpcClientHandle;
  1053. PGPC_ADD_CF_INFO_REQ GpcReq;
  1054. PGPC_ADD_CF_INFO_RES GpcRes;
  1055. PBLOB_BLOCK pBlob = NULL;
  1056. QUEUED_COMPLETION QItem;
  1057. UNICODE_STRING CfInfoName;
  1058. USHORT NameLen = 0;
  1059. if (inputBufferLength < sizeof(GPC_ADD_CF_INFO_REQ)
  1060. ||
  1061. *outputBufferLength < sizeof(GPC_ADD_CF_INFO_RES)
  1062. ) {
  1063. return STATUS_BUFFER_TOO_SMALL;
  1064. }
  1065. GpcReq = (PGPC_ADD_CF_INFO_REQ)ioBuffer;
  1066. GpcRes = (PGPC_ADD_CF_INFO_RES)ioBuffer;
  1067. //Validate CfInfo and CfInfoSize
  1068. if (GpcReq->CfInfoSize >
  1069. inputBufferLength - FIELD_OFFSET(GPC_ADD_CF_INFO_REQ, CfInfo)) {
  1070. return STATUS_INVALID_BUFFER_SIZE;
  1071. }
  1072. if (GpcReq->CfInfoSize < 1) return GPC_STATUS_INVALID_PARAMETER;
  1073. //Validate that the client handle maps on to a CLIENT_BLOCK
  1074. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  1075. GPC_ENUM_CLIENT_TYPE,
  1076. 'PGAC');
  1077. if (GpcClientHandle) {
  1078. //
  1079. // Validate that the client handle is owned by the
  1080. // calling user mode app.
  1081. //
  1082. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  1083. if (Status == GPC_STATUS_SUCCESS)
  1084. {
  1085. Status = privateGpcAddCfInfo(GpcClientHandle,
  1086. GpcReq->CfInfoSize,
  1087. &GpcReq->CfInfo,
  1088. GpcReq->ClientCfInfoContext,
  1089. NULL,
  1090. NULL,
  1091. (PGPC_HANDLE)&pBlob);
  1092. }
  1093. if (NT_SUCCESS(Status)) {
  1094. //
  1095. // including PENDING
  1096. //
  1097. if (Status == GPC_STATUS_PENDING) {
  1098. QItem.OpCode = OP_ADD_CFINFO;
  1099. QItem.ClientHandle = GpcClientHandle;
  1100. QItem.CfInfoHandle = (GPC_HANDLE)pBlob;
  1101. Status = CheckQueuedCompletion(&QItem, Irp);
  1102. }
  1103. if (Status == GPC_STATUS_SUCCESS) {
  1104. GPC_STATUS st = GPC_STATUS_FAILURE;
  1105. GPC_CLIENT_HANDLE NotifiedClientCtx = pBlob->NotifiedClientCtx;
  1106. PCLIENT_BLOCK pNotifiedClient = pBlob->pNotifiedClient;
  1107. GpcRes->GpcCfInfoHandle = (GPC_HANDLE)AllocateHandle(&pBlob->ClHandle, (PVOID)pBlob);
  1108. // what if we cant allocate a handle? fail the add!
  1109. if (!GpcRes->GpcCfInfoHandle) {
  1110. GpcRemoveCfInfo(GpcClientHandle,
  1111. pBlob);
  1112. Status = STATUS_INSUFFICIENT_RESOURCES;
  1113. goto exit;
  1114. }
  1115. if (pNotifiedClient) {
  1116. if (pNotifiedClient->FuncList.ClGetCfInfoName &&
  1117. NotifiedClientCtx) {
  1118. st = pNotifiedClient->FuncList.ClGetCfInfoName(
  1119. pNotifiedClient->ClientCtx,
  1120. NotifiedClientCtx,
  1121. &CfInfoName
  1122. );
  1123. if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
  1124. CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
  1125. //
  1126. // RajeshSu claims this can never happen.
  1127. //
  1128. ASSERT(NT_SUCCESS(st));
  1129. }
  1130. }
  1131. if (NT_SUCCESS(st)) {
  1132. //
  1133. // copy the instance name
  1134. //
  1135. GpcRes->InstanceNameLength = NameLen = CfInfoName.Length;
  1136. RtlMoveMemory(GpcRes->InstanceName,
  1137. CfInfoName.Buffer,
  1138. CfInfoName.Length
  1139. );
  1140. } else {
  1141. //
  1142. // generate a default name
  1143. //
  1144. if (NotifiedClientCtx)
  1145. swprintf(GpcRes->InstanceName, L"Flow %08X", NotifiedClientCtx);
  1146. else
  1147. swprintf(GpcRes->InstanceName, L"Flow <unkonwn name>");
  1148. GpcRes->InstanceNameLength = NameLen = wcslen(GpcRes->InstanceName)*sizeof(WCHAR);
  1149. }
  1150. GpcRes->InstanceName[GpcRes->InstanceNameLength/sizeof(WCHAR)] = L'\0';
  1151. } else {
  1152. pBlob = NULL;
  1153. }
  1154. }
  1155. //
  1156. // release the ref count we got earlier
  1157. //
  1158. exit:
  1159. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAC');
  1160. } else {
  1161. ASSERT(pBlob == NULL);
  1162. Status = GPC_STATUS_INVALID_HANDLE;
  1163. }
  1164. GpcRes->InstanceNameLength = NameLen;
  1165. GpcRes->Status = Status;
  1166. *outputBufferLength = sizeof(GPC_ADD_CF_INFO_RES);
  1167. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  1168. }
  1169. NTSTATUS
  1170. ProxyGpcAddPattern(
  1171. PVOID ioBuffer,
  1172. ULONG inputBufferLength,
  1173. ULONG *outputBufferLength,
  1174. PFILE_OBJECT FileObject,
  1175. BOOLEAN fNewInterface
  1176. )
  1177. {
  1178. NTSTATUS Status;
  1179. GPC_HANDLE GpcClientHandle=NULL;
  1180. GPC_HANDLE GpcCfInfoHandle=NULL;
  1181. CLASSIFICATION_HANDLE ClassificationHandle = 0;
  1182. PGPC_ADD_PATTERN_REQ GpcReq;
  1183. PGPC_ADD_PATTERN_RES GpcRes;
  1184. PVOID Pattern;
  1185. PVOID Mask;
  1186. PPATTERN_BLOCK pPattern;
  1187. PBLOB_BLOCK pBlob = NULL ;
  1188. if (inputBufferLength < sizeof(GPC_ADD_PATTERN_REQ)
  1189. ||
  1190. *outputBufferLength < sizeof(GPC_ADD_PATTERN_RES)
  1191. ) {
  1192. return STATUS_BUFFER_TOO_SMALL;
  1193. }
  1194. if (fNewInterface){
  1195. // Do not allow HTTP to use this IOCTL interface
  1196. //
  1197. if ( KernelMode == ExGetPreviousMode() ){
  1198. return GPC_STATUS_NOT_SUPPORTED;
  1199. }
  1200. }
  1201. GpcReq = (PGPC_ADD_PATTERN_REQ)ioBuffer;
  1202. GpcRes = (PGPC_ADD_PATTERN_RES)ioBuffer;
  1203. //Validate PatternSize and Size of PatternAndMask array
  1204. if (GpcReq->PatternSize > MAX_PATTERN_SIZE) {
  1205. return STATUS_INVALID_PARAMETER;
  1206. }
  1207. if (inputBufferLength - FIELD_OFFSET(GPC_ADD_PATTERN_REQ, PatternAndMask)
  1208. < 2 * GpcReq->PatternSize) {
  1209. return STATUS_BUFFER_TOO_SMALL;
  1210. }
  1211. //
  1212. //Validate that the client handle maps on to a CLIENT_BLOCK
  1213. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  1214. GPC_ENUM_CLIENT_TYPE,
  1215. 'PGAP');
  1216. //
  1217. // Validate that the cfInfo handle maps on to a BLOB_BLOCK
  1218. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle,
  1219. GPC_ENUM_CFINFO_TYPE,
  1220. 'PGAP');
  1221. if (!(GpcClientHandle && GpcCfInfoHandle)){
  1222. Status = GPC_STATUS_INVALID_HANDLE;
  1223. goto exit;
  1224. }
  1225. Pattern = (PVOID)&GpcReq->PatternAndMask;
  1226. Mask = (PVOID)((PCHAR)(&GpcReq->PatternAndMask) + GpcReq->PatternSize);
  1227. //
  1228. // Validate that the client handle is owned by the
  1229. // calling user mode app.
  1230. //
  1231. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  1232. if ( GPC_STATUS_SUCCESS != Status ){
  1233. goto exit;
  1234. }
  1235. //
  1236. // Validate that the client owns the cfinfo
  1237. // to which he wants to link the pattern to
  1238. //
  1239. Status = GpcValidateCfinfoOwner(GpcClientHandle,GpcCfInfoHandle);
  1240. if (GPC_STATUS_SUCCESS != Status) {
  1241. goto exit;
  1242. }
  1243. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  1244. // Priority and Protocol Template Validation
  1245. if (GpcReq->Priority >=
  1246. ((PCLIENT_BLOCK)(GpcClientHandle))->pCfBlock->MaxPriorities ||
  1247. GpcReq->ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX ) {
  1248. Status = GPC_STATUS_INVALID_PARAMETER;
  1249. goto exit;
  1250. }
  1251. // EX IOCTL users should already have their
  1252. // GPC_IP_PATTERN hanging off the
  1253. // BLOB_BLOCK
  1254. if ((fNewInterface) && (!pBlob->Pattern)) {
  1255. Status = GPC_STATUS_INVALID_PARAMETER;
  1256. goto exit;
  1257. }
  1258. //EX IOCTL users only
  1259. if (fNewInterface){
  1260. //Extra code for the new IOCTL.
  1261. // The cfinfo should contain a valid pattern pointer
  1262. // receiverd during the previous call to ProxyGpcAddCfinfoEx
  1263. RtlCopyMemory(Pattern, pBlob->Pattern, sizeof(GPC_IP_PATTERN));
  1264. RtlFillMemory(Mask, sizeof(GPC_IP_PATTERN), 0xff);
  1265. }
  1266. Status = GpcAddPattern(GpcClientHandle,
  1267. GpcReq->ProtocolTemplate,
  1268. Pattern,
  1269. Mask,
  1270. GpcReq->Priority,
  1271. GpcCfInfoHandle,
  1272. (PGPC_HANDLE)&pPattern,
  1273. &ClassificationHandle);
  1274. if (Status == GPC_STATUS_SUCCESS) {
  1275. ASSERT(Pattern);
  1276. GpcRes->GpcPatternHandle = AllocateHandle(&pPattern->ClHandle, (PVOID)pPattern);
  1277. //
  1278. // In certain circs, alloc_HF_handle could return 0.
  1279. // check for that and clean up the mess.
  1280. //
  1281. if (!GpcRes->GpcPatternHandle) {
  1282. //
  1283. // remove the pattern that was just added.
  1284. //
  1285. Status = GpcRemovePattern(GpcClientHandle,
  1286. pPattern);
  1287. //
  1288. // This was really the problem why we got a NULL handle
  1289. //
  1290. Status = GPC_STATUS_RESOURCES;
  1291. }
  1292. }
  1293. exit:
  1294. if (GpcCfInfoHandle) {
  1295. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGAP');
  1296. }
  1297. if (GpcClientHandle) {
  1298. //
  1299. // release the ref count we got earlier
  1300. //
  1301. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGAP');
  1302. }
  1303. ASSERT(Status != GPC_STATUS_PENDING);
  1304. GpcRes->Status = Status;
  1305. GpcRes->ClassificationHandle = ClassificationHandle;
  1306. *outputBufferLength = sizeof(GPC_ADD_PATTERN_RES);
  1307. return STATUS_SUCCESS;
  1308. }
  1309. NTSTATUS
  1310. ProxyGpcModifyCfInfo(
  1311. PVOID ioBuffer,
  1312. ULONG inputBufferLength,
  1313. ULONG *outputBufferLength,
  1314. PIRP Irp,
  1315. PFILE_OBJECT FileObject
  1316. )
  1317. {
  1318. NTSTATUS Status;
  1319. GPC_HANDLE GpcClientHandle;
  1320. GPC_HANDLE GpcCfInfoHandle;
  1321. PGPC_MODIFY_CF_INFO_REQ GpcReq;
  1322. PGPC_MODIFY_CF_INFO_RES GpcRes;
  1323. QUEUED_COMPLETION QItem;
  1324. if (inputBufferLength < sizeof(GPC_MODIFY_CF_INFO_REQ)
  1325. ||
  1326. *outputBufferLength < sizeof(GPC_MODIFY_CF_INFO_RES)
  1327. ) {
  1328. return STATUS_BUFFER_TOO_SMALL;
  1329. }
  1330. GpcReq = (PGPC_MODIFY_CF_INFO_REQ)ioBuffer;
  1331. GpcRes = (PGPC_MODIFY_CF_INFO_RES)ioBuffer;
  1332. if (GpcReq->CfInfoSize >
  1333. inputBufferLength - FIELD_OFFSET(GPC_MODIFY_CF_INFO_REQ, CfInfo)) {
  1334. return STATUS_INVALID_BUFFER_SIZE;
  1335. }
  1336. // Validate that the client handle maps on to a valid CLIENT_BLOCK
  1337. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  1338. GPC_ENUM_CLIENT_TYPE,
  1339. 'PGMP');
  1340. // Validate that the cfInfo handle maps on to a valid BLOB_BLOCK
  1341. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle,
  1342. GPC_ENUM_CFINFO_TYPE,
  1343. 'PGMP');
  1344. if (GpcClientHandle && GpcCfInfoHandle) {
  1345. //
  1346. // Validate that the client handle is owned by the
  1347. // calling user mode app.
  1348. //
  1349. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  1350. if (Status == GPC_STATUS_SUCCESS)
  1351. {
  1352. //
  1353. // Validate that the client only modifies a CfInfo that
  1354. // belongs to him.
  1355. //
  1356. Status = GpcValidateCfinfoOwner (GpcClientHandle , GpcCfInfoHandle);
  1357. if ( Status == GPC_STATUS_SUCCESS )
  1358. {
  1359. Status = GpcModifyCfInfo(GpcClientHandle,
  1360. GpcCfInfoHandle,
  1361. GpcReq->CfInfoSize,
  1362. &GpcReq->CfInfo
  1363. );
  1364. }
  1365. }
  1366. if (Status == GPC_STATUS_PENDING) {
  1367. QItem.OpCode = OP_MODIFY_CFINFO;
  1368. QItem.ClientHandle = GpcClientHandle;
  1369. QItem.CfInfoHandle = GpcCfInfoHandle;
  1370. Status = CheckQueuedCompletion(&QItem, Irp);
  1371. }
  1372. } else {
  1373. Status = STATUS_INVALID_HANDLE;
  1374. }
  1375. if (GpcCfInfoHandle) {
  1376. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGMP');
  1377. }
  1378. if (GpcClientHandle) {
  1379. //
  1380. // release the ref count we got earlier
  1381. //
  1382. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGMP');
  1383. }
  1384. GpcRes->Status = Status;
  1385. *outputBufferLength = sizeof(GPC_MODIFY_CF_INFO_RES);
  1386. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  1387. }
  1388. NTSTATUS
  1389. ProxyGpcRemoveCfInfo(
  1390. PVOID ioBuffer,
  1391. ULONG inputBufferLength,
  1392. ULONG *outputBufferLength,
  1393. PIRP Irp,
  1394. PFILE_OBJECT FileObject,
  1395. BOOLEAN fNewInterface
  1396. )
  1397. {
  1398. NTSTATUS Status;
  1399. GPC_HANDLE GpcClientHandle;
  1400. GPC_HANDLE GpcCfInfoHandle;
  1401. PGPC_REMOVE_CF_INFO_REQ GpcReq;
  1402. PGPC_REMOVE_CF_INFO_RES GpcRes;
  1403. QUEUED_COMPLETION QItem;
  1404. if (inputBufferLength < sizeof(GPC_REMOVE_CF_INFO_REQ)
  1405. ||
  1406. *outputBufferLength < sizeof(GPC_REMOVE_CF_INFO_RES)
  1407. ) {
  1408. return STATUS_BUFFER_TOO_SMALL;
  1409. }
  1410. if (fNewInterface){
  1411. // Do not allow HTTP to use this IOCTL interface
  1412. //
  1413. if ( KernelMode == ExGetPreviousMode() ){
  1414. return GPC_STATUS_NOT_SUPPORTED;
  1415. }
  1416. }
  1417. GpcReq = (PGPC_REMOVE_CF_INFO_REQ)ioBuffer;
  1418. GpcRes = (PGPC_REMOVE_CF_INFO_RES)ioBuffer;
  1419. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  1420. GPC_ENUM_CLIENT_TYPE,
  1421. 'PGRC');
  1422. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcCfInfoHandle,
  1423. GPC_ENUM_CFINFO_TYPE,
  1424. 'PGRC');
  1425. if (GpcClientHandle && GpcCfInfoHandle) {
  1426. //
  1427. // Validate that the client handle is owned by the
  1428. // calling user mode app.
  1429. //
  1430. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  1431. if (Status == GPC_STATUS_SUCCESS)
  1432. {
  1433. //
  1434. // Validate that the client only removes a cfinfo
  1435. // that belongs to him
  1436. //
  1437. Status = GpcValidateCfinfoOwner (GpcClientHandle , GpcCfInfoHandle);
  1438. if ( Status == GPC_STATUS_SUCCESS )
  1439. {
  1440. if (fNewInterface){
  1441. Status = privateGpcRemoveCfInfo(GpcClientHandle,
  1442. GpcCfInfoHandle,
  1443. GPC_FLAGS_USERMODE_CLIENT
  1444. |GPC_FLAGS_USERMODE_CLIENT_EX);
  1445. }
  1446. else{
  1447. Status = privateGpcRemoveCfInfo(GpcClientHandle,
  1448. GpcCfInfoHandle,
  1449. GPC_FLAGS_USERMODE_CLIENT);
  1450. }
  1451. }
  1452. }
  1453. if (Status == GPC_STATUS_PENDING) {
  1454. QItem.OpCode = OP_REMOVE_CFINFO;
  1455. QItem.ClientHandle = GpcClientHandle;
  1456. QItem.CfInfoHandle = GpcCfInfoHandle;
  1457. Status = CheckQueuedCompletion(&QItem, Irp);
  1458. }
  1459. } else {
  1460. Status = STATUS_INVALID_HANDLE;
  1461. }
  1462. if (GpcCfInfoHandle) {
  1463. //
  1464. // release the ref count we got earlier
  1465. //
  1466. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGRC');
  1467. }
  1468. if (GpcClientHandle) {
  1469. //
  1470. // release the ref count we got earlier
  1471. //
  1472. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGRC');
  1473. }
  1474. GpcRes->Status = Status;
  1475. *outputBufferLength = sizeof(GPC_REMOVE_CF_INFO_RES);
  1476. return (Status == GPC_STATUS_PENDING) ? STATUS_PENDING : STATUS_SUCCESS;
  1477. }
  1478. NTSTATUS
  1479. ProxyGpcRemovePattern(
  1480. PVOID ioBuffer,
  1481. ULONG inputBufferLength,
  1482. ULONG *outputBufferLength,
  1483. PFILE_OBJECT FileObject,
  1484. BOOLEAN fNewInterface
  1485. )
  1486. {
  1487. NTSTATUS Status;
  1488. GPC_HANDLE GpcClientHandle;
  1489. GPC_HANDLE GpcPatternHandle;
  1490. PGPC_REMOVE_PATTERN_REQ GpcReq;
  1491. PGPC_REMOVE_PATTERN_RES GpcRes;
  1492. if (inputBufferLength < sizeof(GPC_REMOVE_PATTERN_REQ)
  1493. ||
  1494. *outputBufferLength < sizeof(GPC_REMOVE_PATTERN_RES)
  1495. ) {
  1496. return STATUS_BUFFER_TOO_SMALL;
  1497. }
  1498. if (fNewInterface){
  1499. // Do not allow HTTP to use this IOCTL interface
  1500. //
  1501. if ( KernelMode == ExGetPreviousMode() ){
  1502. return GPC_STATUS_NOT_SUPPORTED;
  1503. }
  1504. }
  1505. GpcReq = (PGPC_REMOVE_PATTERN_REQ)ioBuffer;
  1506. GpcRes = (PGPC_REMOVE_PATTERN_RES)ioBuffer;
  1507. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  1508. GPC_ENUM_CLIENT_TYPE,
  1509. 'PGRP');
  1510. GpcPatternHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->GpcPatternHandle,
  1511. GPC_ENUM_PATTERN_TYPE,
  1512. 'PGRP');
  1513. if (!(GpcClientHandle && GpcPatternHandle) ) {
  1514. Status = GPC_STATUS_INVALID_HANDLE;
  1515. goto exit;
  1516. }
  1517. //
  1518. // Validate that the client handle is owned by the
  1519. // calling user mode app.
  1520. //
  1521. Status = GpcValidateClientOwner(GpcClientHandle, FileObject);
  1522. if (GPC_STATUS_SUCCESS != Status) {
  1523. goto exit;
  1524. }
  1525. //
  1526. // Validate that the client owns the Pattern that it is trying to delete
  1527. //
  1528. Status = GpcValidatePatternOwner(GpcClientHandle,GpcPatternHandle);
  1529. if (GPC_STATUS_SUCCESS != Status){
  1530. goto exit;
  1531. }
  1532. Status = GpcRemovePattern(GpcClientHandle,
  1533. GpcPatternHandle);
  1534. exit:
  1535. if (GpcPatternHandle) {
  1536. REFDEL(&((PPATTERN_BLOCK)GpcPatternHandle)->RefCount, 'PGRP');
  1537. }
  1538. if (GpcClientHandle) {
  1539. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGRP');
  1540. }
  1541. ASSERT(Status != GPC_STATUS_PENDING);
  1542. GpcRes->Status = Status;
  1543. *outputBufferLength = sizeof(GPC_REMOVE_PATTERN_RES);
  1544. return STATUS_SUCCESS;
  1545. }
  1546. NTSTATUS
  1547. ProxyGpcEnumCfInfo(
  1548. PVOID ioBuffer,
  1549. ULONG inputBufferLength,
  1550. ULONG *outputBufferLength,
  1551. PFILE_OBJECT FileObject
  1552. )
  1553. {
  1554. NTSTATUS Status;
  1555. PGPC_ENUM_CFINFO_REQ GpcReq;
  1556. PGPC_ENUM_CFINFO_RES GpcRes;
  1557. ULONG Size;
  1558. ULONG TotalCount;
  1559. GPC_HANDLE GpcClientHandle;
  1560. GPC_HANDLE GpcCfInfoHandle;
  1561. GPC_HANDLE EnumHandle;
  1562. PBLOB_BLOCK pBlob;
  1563. if (inputBufferLength < sizeof(GPC_ENUM_CFINFO_REQ)
  1564. ||
  1565. *outputBufferLength < sizeof(GPC_ENUM_CFINFO_RES)
  1566. ) {
  1567. return STATUS_BUFFER_TOO_SMALL;
  1568. }
  1569. GpcReq = (PGPC_ENUM_CFINFO_REQ)ioBuffer;
  1570. GpcRes = (PGPC_ENUM_CFINFO_RES)ioBuffer;
  1571. GpcClientHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->ClientHandle,
  1572. GPC_ENUM_CLIENT_TYPE,
  1573. 'PGEC');
  1574. GpcCfInfoHandle = (GPC_HANDLE)GetHandleObjectWithRef(GpcReq->EnumHandle,
  1575. GPC_ENUM_CFINFO_TYPE,
  1576. 'PGEC');
  1577. if (GpcReq->EnumHandle != NULL && GpcCfInfoHandle == NULL) {
  1578. //
  1579. // the flow has been deleted during enumeration
  1580. //
  1581. Status = STATUS_DATA_ERROR;
  1582. } else if (GpcClientHandle) {
  1583. TotalCount = GpcReq->CfInfoCount;
  1584. EnumHandle = GpcReq->EnumHandle;
  1585. Size = *outputBufferLength - FIELD_OFFSET(GPC_ENUM_CFINFO_RES,
  1586. EnumBuffer);
  1587. //
  1588. // save the blob pointer with the one extra ref count
  1589. // since we called GetHandleObjectWithRef
  1590. //
  1591. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  1592. Status = GpcEnumCfInfo(GpcClientHandle,
  1593. &GpcCfInfoHandle,
  1594. &EnumHandle,
  1595. &TotalCount,
  1596. &Size,
  1597. GpcRes->EnumBuffer
  1598. );
  1599. if (pBlob) {
  1600. REFDEL(&pBlob->RefCount, 'PGEC');
  1601. }
  1602. if (Status == GPC_STATUS_SUCCESS) {
  1603. //
  1604. // fill in the results
  1605. //
  1606. GpcRes->TotalCfInfo = TotalCount;
  1607. GpcRes->EnumHandle = EnumHandle;
  1608. *outputBufferLength = Size + FIELD_OFFSET(GPC_ENUM_CFINFO_RES,
  1609. EnumBuffer);
  1610. }
  1611. } else {
  1612. if (GpcCfInfoHandle) {
  1613. REFDEL(&((PBLOB_BLOCK)GpcCfInfoHandle)->RefCount, 'PGEC');
  1614. }
  1615. Status = STATUS_INVALID_HANDLE;
  1616. }
  1617. if (GpcClientHandle) {
  1618. //
  1619. // release the ref count we got earlier
  1620. //
  1621. REFDEL(&((PCLIENT_BLOCK)GpcClientHandle)->RefCount, 'PGEC');
  1622. }
  1623. ASSERT(Status != GPC_STATUS_PENDING);
  1624. GpcRes->Status = Status;
  1625. return STATUS_SUCCESS;
  1626. }
  1627. VOID
  1628. CancelPendingIrpCfInfo(
  1629. IN PDEVICE_OBJECT Device,
  1630. IN PIRP Irp
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. Cancels an outstanding IRP request for a CfInfo request.
  1635. Arguments:
  1636. Device - The device on which the request was issued.
  1637. Irp - Pointer to I/O request packet to cancel.
  1638. Return Value:
  1639. None
  1640. Notes:
  1641. This function is called with cancel spinlock held. It must be
  1642. released before the function returns.
  1643. The cfinfo block associated with this request cannot be
  1644. freed until the request completes. The completion routine will
  1645. free it.
  1646. --*/
  1647. {
  1648. PPENDING_IRP pPendingIrp = NULL;
  1649. PPENDING_IRP pItem;
  1650. PLIST_ENTRY pEntry;
  1651. #if DBG
  1652. KIRQL irql = KeGetCurrentIrql();
  1653. HANDLE thrd = PsGetCurrentThreadId();
  1654. #endif
  1655. DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: Irp=0x%X\n",
  1656. (ULONG_PTR)Irp));
  1657. TRACE(IOCTL, Irp, 0, "CancelPendingIrpCfInfo:");
  1658. TRACE(LOCKS, thrd, irql, "CancelPendingIrpCfInfo:");
  1659. for ( pEntry = PendingIrpCfInfoList.Flink;
  1660. pEntry != &PendingIrpCfInfoList;
  1661. pEntry = pEntry->Flink ) {
  1662. pItem = CONTAINING_RECORD(pEntry, PENDING_IRP, Linkage);
  1663. if (pItem->Irp == Irp) {
  1664. pPendingIrp = pItem;
  1665. GpcRemoveEntryList(pEntry);
  1666. IoSetCancelRoutine(pPendingIrp->Irp, NULL);
  1667. break;
  1668. }
  1669. }
  1670. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1671. if (pPendingIrp != NULL) {
  1672. DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: found PendingIrp=0x%X\n",
  1673. (ULONG_PTR)pPendingIrp));
  1674. TRACE(IOCTL, Irp, pPendingIrp, "CancelPendingIrpCfInfo.PendingIrp:");
  1675. //
  1676. // Free the PENDING_IRP structure. The control block will be freed
  1677. // when the request completes.
  1678. //
  1679. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1680. //
  1681. // Complete the IRP.
  1682. //
  1683. Irp->IoStatus.Information = 0;
  1684. Irp->IoStatus.Status = STATUS_CANCELLED;
  1685. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1686. } else {
  1687. DBGPRINT(IOCTL, ("CancelPendingIrpCfInfo: PendingIrp not found\n"));
  1688. TRACE(IOCTL, Irp, 0, "CancelPendingIrpCfInfo.NoPendingIrp:");
  1689. }
  1690. #if DBG
  1691. irql = KeGetCurrentIrql();
  1692. #endif
  1693. TRACE(LOCKS, thrd, irql, "CancelPendingIrpCfInfo (end)");
  1694. return;
  1695. }
  1696. VOID
  1697. CancelPendingIrpNotify(
  1698. IN PDEVICE_OBJECT Device,
  1699. IN PIRP Irp
  1700. )
  1701. /*++
  1702. Routine Description:
  1703. Cancels an outstanding IRP request for a notification.
  1704. Arguments:
  1705. Device - The device on which the request was issued.
  1706. Irp - Pointer to I/O request packet to cancel.
  1707. Return Value:
  1708. None
  1709. Notes:
  1710. This function is called with cancel spinlock held. It must be
  1711. released before the function returns.
  1712. --*/
  1713. {
  1714. PPENDING_IRP pPendingIrp = NULL;
  1715. PPENDING_IRP pItem;
  1716. PLIST_ENTRY pEntry;
  1717. #if DBG
  1718. KIRQL irql = KeGetCurrentIrql();
  1719. HANDLE thrd = PsGetCurrentThreadId();
  1720. #endif
  1721. DBGPRINT(IOCTL, ("CancelPendingIrpNotify: Irp=0x%X\n",
  1722. (ULONG_PTR)Irp));
  1723. TRACE(IOCTL, Irp, 0, "CancelPendingIrpNotify:");
  1724. TRACE(LOCKS, thrd, irql, "CancelPendingIrpNotify:");
  1725. for ( pEntry = PendingIrpNotifyList.Flink;
  1726. pEntry != &PendingIrpNotifyList;
  1727. pEntry = pEntry->Flink ) {
  1728. pItem = CONTAINING_RECORD(pEntry, PENDING_IRP, Linkage);
  1729. if (pItem->Irp == Irp) {
  1730. pPendingIrp = pItem;
  1731. GpcRemoveEntryList(pEntry);
  1732. IoSetCancelRoutine(pPendingIrp->Irp, NULL);
  1733. break;
  1734. }
  1735. }
  1736. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1737. if (pPendingIrp != NULL) {
  1738. DBGPRINT(IOCTL, ("CancelPendingIrpNotify: Found a PendingIrp=0x%X\n",
  1739. (ULONG_PTR)pPendingIrp));
  1740. TRACE(IOCTL, Irp, pPendingIrp, "CancelPendingIrpNotify.PendingIrp:");
  1741. //
  1742. // Free the PENDING_IRP structure.
  1743. //
  1744. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1745. //
  1746. // Complete the IRP.
  1747. //
  1748. Irp->IoStatus.Information = 0;
  1749. Irp->IoStatus.Status = STATUS_CANCELLED;
  1750. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1751. } else {
  1752. DBGPRINT(IOCTL, ("CancelPendingIrpNotify: PendingIrp not found\n"));
  1753. TRACE(IOCTL, Irp, 0, "CancelPendingIrpNotify.NoPendingIrp:");
  1754. }
  1755. #if DBG
  1756. irql = KeGetCurrentIrql();
  1757. #endif
  1758. TRACE(LOCKS, thrd, irql, "CancelPendingIrpNotify (end)");
  1759. return;
  1760. }
  1761. VOID
  1762. UMClientRemoveCfInfoNotify(
  1763. IN PCLIENT_BLOCK pClient,
  1764. IN PBLOB_BLOCK pBlob
  1765. )
  1766. /*++
  1767. Routine Description:
  1768. Notify user mode client that the CfInfo is deleted.
  1769. This will dequeue a pending IRP and will complete it.
  1770. If there is no pending IRP, a GPC_NOTIFY_REQUEST_RES buffer
  1771. will be queued until we get an IRP down the stack.
  1772. Arguments:
  1773. pClient - the notified client
  1774. pBlob - the deleted cfinfo
  1775. Return Value:
  1776. None
  1777. --*/
  1778. {
  1779. KIRQL oldIrql;
  1780. PIRP pIrp;
  1781. PPENDING_IRP pPendingIrp = NULL;
  1782. PLIST_ENTRY pEntry;
  1783. PQUEUED_NOTIFY pQItem;
  1784. PGPC_NOTIFY_REQUEST_RES GpcRes;
  1785. ASSERT(pClient == pBlob->pOwnerClient);
  1786. DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: pClient=0x%X, pBlob=0x%X\n",
  1787. (ULONG_PTR)pClient, (ULONG_PTR)pBlob));
  1788. TRACE(IOCTL, pClient, pBlob, "UMClientRemoveCfInfoNotify:");
  1789. //
  1790. // Find the request IRP on the pending list.
  1791. //
  1792. IoAcquireCancelSpinLock(&oldIrql);
  1793. for ( pEntry = PendingIrpNotifyList.Flink;
  1794. pEntry != &PendingIrpNotifyList;
  1795. pEntry = pEntry->Flink ) {
  1796. pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
  1797. if (pPendingIrp->FileObject == pClient->pFileObject) {
  1798. //
  1799. // that's the pending request
  1800. //
  1801. pIrp = pPendingIrp->Irp;
  1802. IoSetCancelRoutine(pIrp, NULL);
  1803. GpcRemoveEntryList(pEntry);
  1804. break;
  1805. } else {
  1806. pPendingIrp = NULL;
  1807. }
  1808. }
  1809. if (pPendingIrp == NULL) {
  1810. //
  1811. // No IRP, we need to queue the notification block
  1812. //
  1813. DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: No pending IRP found\n"
  1814. ));
  1815. TRACE(IOCTL,
  1816. pClient->ClientCtx,
  1817. pBlob->arClientCtx[pClient->AssignedIndex],
  1818. "UMClientRemoveCfInfoNotify.NoPendingIrp:");
  1819. GpcAllocFromLL(&pQItem, &QueuedNotificationLL, QueuedNotificationTag);
  1820. if (pQItem) {
  1821. pQItem->FileObject = pClient->pFileObject;
  1822. //
  1823. // fill the item
  1824. //
  1825. pQItem->NotifyRes.ClientCtx = pClient->ClientCtx;
  1826. pQItem->NotifyRes.NotificationCtx =
  1827. (ULONG_PTR)pBlob->arClientCtx[pClient->AssignedIndex];
  1828. pQItem->NotifyRes.SubCode = GPC_NOTIFY_CFINFO_CLOSED;
  1829. pQItem->NotifyRes.Reason = 0; // for now...
  1830. pQItem->NotifyRes.Param1 = 0; // for now...
  1831. GpcInsertTailList(&QueuedNotificationList, &pQItem->Linkage);
  1832. }
  1833. }
  1834. IoReleaseCancelSpinLock(oldIrql);
  1835. if (pPendingIrp) {
  1836. //
  1837. // found an IRP, fill and complete
  1838. //
  1839. DBGPRINT(IOCTL, ("UMClientRemoveCfInfoNotify: Pending IRP found=0x%X\n",
  1840. (ULONG_PTR)pIrp));
  1841. TRACE(IOCTL,
  1842. pClient->ClientCtx,
  1843. pBlob->arClientCtx[pClient->AssignedIndex],
  1844. "UMClientRemoveCfInfoNotify.PendingIrp:");
  1845. GpcRes = (PGPC_NOTIFY_REQUEST_RES)pIrp->AssociatedIrp.SystemBuffer;
  1846. GpcRes->ClientCtx = pClient->ClientCtx;
  1847. GpcRes->NotificationCtx =
  1848. (ULONG_PTR)pBlob->arClientCtx[pClient->AssignedIndex];
  1849. GpcRes->SubCode = GPC_NOTIFY_CFINFO_CLOSED;
  1850. GpcRes->Reason = 0; // for now...
  1851. GpcRes->Param1 = 0; // for now...
  1852. //
  1853. // complete the IRP
  1854. //
  1855. pIrp->IoStatus.Information = sizeof(GPC_NOTIFY_REQUEST_REQ);
  1856. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1857. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  1858. //
  1859. // We can free the pending irp item
  1860. //
  1861. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1862. }
  1863. //
  1864. // for now - complete the operation
  1865. // we should probably let the User Mode client do it,
  1866. // but this complicates things a little...
  1867. //
  1868. GpcRemoveCfInfoNotifyComplete((GPC_HANDLE)pClient,
  1869. (GPC_HANDLE)pBlob,
  1870. GPC_STATUS_SUCCESS
  1871. );
  1872. return;
  1873. }
  1874. VOID
  1875. UMCfInfoComplete(
  1876. IN GPC_COMPLETION_OP OpCode,
  1877. IN PCLIENT_BLOCK pClient,
  1878. IN PBLOB_BLOCK pBlob,
  1879. IN GPC_STATUS Status
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. This is the completion routine for any pending CfInfo request.
  1884. It will search the pending IRP CfInfo list for a matching CfInfo
  1885. structure that has been stored while the Add, Modify or Remove
  1886. request returned PENDING. The client must be the CfInfo owner,
  1887. otherwise we would have never got here.
  1888. If an IRP is not found, it means the operation completed *before*
  1889. we got back the PENDING status, which is perfectly legal.
  1890. In this case, we queue a completion item and return.
  1891. Arguments:
  1892. OpCode - the code of the completion (add, modify or remove)
  1893. pClient - the notified client
  1894. pBlob - the deleted cfinfo
  1895. Status - the reported status
  1896. Return Value:
  1897. None
  1898. --*/
  1899. {
  1900. typedef union _GPC_CF_INFO_RES {
  1901. GPC_ADD_CF_INFO_RES AddRes;
  1902. GPC_MODIFY_CF_INFO_RES ModifyRes;
  1903. GPC_REMOVE_CF_INFO_RES RemoveRes;
  1904. } GPC_CF_INFO_RES;
  1905. KIRQL oldIrql;
  1906. PIRP pIrp;
  1907. PIO_STACK_LOCATION pIrpSp;
  1908. PPENDING_IRP pPendingIrp = NULL;
  1909. PLIST_ENTRY pEntry;
  1910. GPC_CF_INFO_RES *GpcRes;
  1911. ULONG outputBuferLength;
  1912. //PQUEUED_COMPLETION pQItem;
  1913. //ASSERT(pClient == pBlob->pOwnerClient);
  1914. DBGPRINT(IOCTL, ("UMCfInfoComplete: pClient=0x%X, pBlob=0x%X, Status=0x%X\n",
  1915. (ULONG_PTR)pClient, (ULONG_PTR)pBlob, Status));
  1916. TRACE(IOCTL, OpCode, pClient, "UMCfInfoComplete:");
  1917. TRACE(IOCTL, pBlob, Status, "UMCfInfoComplete:");
  1918. //
  1919. // Find the request IRP on the pending list.
  1920. //
  1921. IoAcquireCancelSpinLock(&oldIrql);
  1922. for ( pEntry = PendingIrpCfInfoList.Flink;
  1923. pEntry != &PendingIrpCfInfoList;
  1924. pEntry = pEntry->Flink ) {
  1925. pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
  1926. if (pPendingIrp->QComp.CfInfoHandle == (GPC_HANDLE)pBlob
  1927. &&
  1928. pPendingIrp->QComp.OpCode == OpCode ) {
  1929. //
  1930. // that's the pending request
  1931. //
  1932. pIrp = pPendingIrp->Irp;
  1933. ASSERT(pIrp);
  1934. IoSetCancelRoutine(pIrp, NULL);
  1935. GpcRemoveEntryList(pEntry);
  1936. break;
  1937. } else {
  1938. pPendingIrp = NULL;
  1939. }
  1940. }
  1941. if (pPendingIrp == NULL) {
  1942. //
  1943. // No IRP, we need to queue a completion block
  1944. //
  1945. DBGPRINT(IOCTL, ("UMCfInfoComplete: No pending IRP found\n"));
  1946. TRACE(IOCTL, pBlob, Status, "UMCfInfoComplete.NoPendingIrp:");
  1947. GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
  1948. if (pPendingIrp) {
  1949. pPendingIrp->Irp = NULL;
  1950. pPendingIrp->FileObject = pClient->pFileObject;
  1951. pPendingIrp->QComp.OpCode = OpCode;
  1952. pPendingIrp->QComp.ClientHandle = (GPC_HANDLE)pClient;
  1953. pPendingIrp->QComp.CfInfoHandle = (GPC_HANDLE)pBlob;
  1954. pPendingIrp->QComp.Status = Status;
  1955. GpcInsertTailList(&QueuedCompletionList, &pPendingIrp->Linkage);
  1956. }
  1957. IoReleaseCancelSpinLock(oldIrql);
  1958. return;
  1959. }
  1960. IoReleaseCancelSpinLock(oldIrql);
  1961. ASSERT(pPendingIrp && pIrp);
  1962. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1963. GpcRes = (GPC_CF_INFO_RES *)pIrp->AssociatedIrp.SystemBuffer;
  1964. DBGPRINT(IOCTL, ("UMCfInfoComplete: Pending IRP found=0x%X, Ioctl=0x%X\n",
  1965. (ULONG_PTR)pIrp,
  1966. pIrpSp->Parameters.DeviceIoControl.IoControlCode
  1967. ));
  1968. TRACE(IOCTL,
  1969. pIrp,
  1970. pIrpSp->Parameters.DeviceIoControl.IoControlCode,
  1971. "UMCfInfoComplete.PendingIrp:");
  1972. switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
  1973. case IOCTL_GPC_ADD_CF_INFO:
  1974. ASSERT(OpCode == OP_ADD_CFINFO);
  1975. ASSERT(pBlob->State == GPC_STATE_ADD);
  1976. GpcRes->AddRes.Status = Status;
  1977. GpcRes->AddRes.ClientCtx = pClient->ClientCtx;
  1978. GpcRes->AddRes.CfInfoCtx = pBlob->OwnerClientCtx;
  1979. GpcRes->AddRes.GpcCfInfoHandle = pBlob->ClHandle;
  1980. if (Status == GPC_STATUS_SUCCESS) {
  1981. UNICODE_STRING CfInfoName;
  1982. if (pBlob->pNotifiedClient) {
  1983. GPC_STATUS st = GPC_STATUS_FAILURE;
  1984. if (pBlob->pNotifiedClient->FuncList.ClGetCfInfoName) {
  1985. ASSERT(pBlob->NotifiedClientCtx);
  1986. pBlob->pNotifiedClient->FuncList.ClGetCfInfoName(
  1987. pBlob->pNotifiedClient->ClientCtx,
  1988. pBlob->NotifiedClientCtx,
  1989. &CfInfoName
  1990. );
  1991. if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
  1992. CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
  1993. }
  1994. if (!NT_SUCCESS(st)) {
  1995. //
  1996. // generate a default name
  1997. //
  1998. swprintf(CfInfoName.Buffer, L"Flow %08X", pBlob->NotifiedClientCtx);
  1999. CfInfoName.Length = wcslen(CfInfoName.Buffer)*sizeof(WCHAR);
  2000. }
  2001. //
  2002. // copy the instance name
  2003. //
  2004. GpcRes->AddRes.InstanceNameLength = CfInfoName.Length;
  2005. NdisMoveMemory(GpcRes->AddRes.InstanceName,
  2006. CfInfoName.Buffer,
  2007. CfInfoName.Length
  2008. );
  2009. }
  2010. }
  2011. outputBuferLength = sizeof(GPC_ADD_CF_INFO_RES);
  2012. break;
  2013. case IOCTL_GPC_MODIFY_CF_INFO:
  2014. ASSERT(OpCode == OP_MODIFY_CFINFO);
  2015. ASSERT(pBlob->State == GPC_STATE_MODIFY);
  2016. GpcRes->ModifyRes.Status = Status;
  2017. GpcRes->ModifyRes.ClientCtx = pClient->ClientCtx;
  2018. GpcRes->ModifyRes.CfInfoCtx = pBlob->OwnerClientCtx;
  2019. outputBuferLength = sizeof(GPC_MODIFY_CF_INFO_RES);
  2020. break;
  2021. case IOCTL_GPC_REMOVE_CF_INFO:
  2022. ASSERT(OpCode == OP_REMOVE_CFINFO);
  2023. ASSERT(pBlob->State == GPC_STATE_REMOVE);
  2024. GpcRes->RemoveRes.Status = Status;
  2025. GpcRes->RemoveRes.ClientCtx = pClient->ClientCtx;
  2026. GpcRes->RemoveRes.CfInfoCtx = pBlob->OwnerClientCtx;
  2027. outputBuferLength = sizeof(GPC_REMOVE_CF_INFO_RES);
  2028. break;
  2029. default:
  2030. ASSERT(0);
  2031. }
  2032. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  2033. //
  2034. // Complete the IRP.
  2035. //
  2036. pIrp->IoStatus.Information = outputBuferLength;
  2037. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2038. DBGPRINT(IOCTL, ("UMCfInfoComplete: Completing IRP =0x%X, Status=0x%X\n",
  2039. (ULONG_PTR)pIrp, Status ));
  2040. TRACE(IOCTL, pIrp, Status, "UMCfInfoComplete.Completing:");
  2041. IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  2042. return;
  2043. }
  2044. NTSTATUS
  2045. CheckQueuedNotification(
  2046. IN PIRP Irp,
  2047. IN OUT ULONG *outputBufferLength
  2048. )
  2049. /*++
  2050. Routine Description:
  2051. This routine will check for a queued notification structrue,
  2052. and it will fill the ioBuffer in the IRP if one has been found
  2053. and return STATUS_SUCCESS. This should cover the case where
  2054. the IRP was not available when the notification was generated.
  2055. O/w the routine returns STATUS_PENDING.
  2056. Arguments:
  2057. Irp - the incoming IRP
  2058. Return Value:
  2059. STATUS_SUCCESS or STATUS_PENDING
  2060. --*/
  2061. {
  2062. KIRQL oldIrql;
  2063. PIO_STACK_LOCATION pIrpSp;
  2064. PQUEUED_NOTIFY pQItem = NULL;
  2065. PLIST_ENTRY pEntry;
  2066. NTSTATUS Status;
  2067. PPENDING_IRP pPendingIrp;
  2068. DBGPRINT(IOCTL, ("CheckQueuedNotification: IRP =0x%X\n",
  2069. (ULONG_PTR)Irp));
  2070. TRACE(IOCTL, Irp, 0, "CheckQueuedNotification:");
  2071. if (*outputBufferLength < sizeof(GPC_NOTIFY_REQUEST_RES)) {
  2072. return STATUS_BUFFER_TOO_SMALL;
  2073. }
  2074. pIrpSp = IoGetCurrentIrpStackLocation(Irp);
  2075. IoAcquireCancelSpinLock(&oldIrql);
  2076. for ( pEntry = QueuedNotificationList.Flink;
  2077. pEntry != &QueuedNotificationList;
  2078. pEntry = pEntry->Flink ) {
  2079. pQItem = CONTAINING_RECORD( pEntry, QUEUED_NOTIFY, Linkage);
  2080. if (pQItem->FileObject == pIrpSp->FileObject) {
  2081. //
  2082. // the queued item if for this file object
  2083. //
  2084. GpcRemoveEntryList(pEntry);
  2085. break;
  2086. } else {
  2087. pQItem = NULL;
  2088. }
  2089. }
  2090. if (pQItem) {
  2091. //
  2092. // We found something on the queue, copy it to the IRP
  2093. // and delete the item
  2094. //
  2095. DBGPRINT(IOCTL, ("CheckQueuedNotification: found QItem =0x%X\n",
  2096. (ULONG_PTR)pQItem));
  2097. TRACE(IOCTL,
  2098. pQItem,
  2099. pQItem->NotifyRes.ClientCtx,
  2100. "CheckQueuedNotification.QItem:");
  2101. ASSERT(*outputBufferLength >= sizeof(GPC_NOTIFY_REQUEST_RES));
  2102. NdisMoveMemory(Irp->AssociatedIrp.SystemBuffer,
  2103. &pQItem->NotifyRes,
  2104. sizeof(GPC_NOTIFY_REQUEST_RES) );
  2105. GpcFreeToLL(pQItem, &QueuedNotificationLL, QueuedNotificationTag);
  2106. *outputBufferLength = sizeof(GPC_NOTIFY_REQUEST_RES);
  2107. Status = STATUS_SUCCESS;
  2108. } else {
  2109. DBGPRINT(IOCTL, ("CheckQueuedNotification: QItem not found...PENDING\n"
  2110. ));
  2111. TRACE(IOCTL, 0, 0, "CheckQueuedNotification.NoQItem:");
  2112. GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
  2113. if (pPendingIrp != NULL) {
  2114. //
  2115. // add the IRP on the pending notification list
  2116. //
  2117. DBGPRINT(IOCTL, ("CheckQueuedNotification: adding IRP=0x%X to list=0x%X\n",
  2118. (ULONG_PTR)Irp, (ULONG_PTR)pIrpSp ));
  2119. TRACE(IOCTL, Irp, pIrpSp, "CheckQueuedNotification.Irp:");
  2120. pPendingIrp->Irp = Irp;
  2121. pPendingIrp->FileObject = pIrpSp->FileObject;
  2122. if (!Irp->Cancel) {
  2123. IoSetCancelRoutine(Irp, CancelPendingIrpNotify);
  2124. GpcInsertTailList(&PendingIrpNotifyList, &(pPendingIrp->Linkage));
  2125. Status = STATUS_PENDING;
  2126. } else {
  2127. DBGPRINT(IOCTL, ("CheckQueuedNotification: Status Cacelled: IRP=0x%X\n",
  2128. (ULONG_PTR)Irp ));
  2129. TRACE(IOCTL, Irp, pIrpSp, "CheckQueuedNotification.Cancelled:");
  2130. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  2131. Status = STATUS_CANCELLED;
  2132. }
  2133. } else {
  2134. Status = STATUS_INSUFFICIENT_RESOURCES;
  2135. }
  2136. *outputBufferLength = 0;
  2137. }
  2138. IoReleaseCancelSpinLock(oldIrql);
  2139. return Status;
  2140. }
  2141. NTSTATUS
  2142. CheckQueuedCompletion(
  2143. IN PQUEUED_COMPLETION pQItem,
  2144. IN PIRP Irp
  2145. )
  2146. /*++
  2147. Routine Description:
  2148. This routine will check for a queued completion structrue
  2149. with the same CfInfoHandle, and it will return it if found.
  2150. The original queued memory block is release here.
  2151. If not found, the returned status is PENDING, o/w the queued status
  2152. is returned.
  2153. Arguments:
  2154. pQItem - pass in the CfInfoHandle and ClientHandle
  2155. Return Value:
  2156. Queued status or STATUS_PENDING
  2157. --*/
  2158. {
  2159. KIRQL oldIrql;
  2160. PLIST_ENTRY pEntry;
  2161. NTSTATUS Status;
  2162. PPENDING_IRP pPendingIrp = NULL;
  2163. PIO_STACK_LOCATION irpStack;
  2164. DBGPRINT(IOCTL, ("CheckQueuedCompletion: pQItem=0x%X\n",
  2165. (ULONG_PTR)pQItem));
  2166. TRACE(IOCTL,
  2167. pQItem->OpCode,
  2168. pQItem->ClientHandle,
  2169. "CheckQueuedCompletion:");
  2170. TRACE(IOCTL,
  2171. pQItem->CfInfoHandle,
  2172. pQItem->Status,
  2173. "CheckQueuedCompletion:");
  2174. IoAcquireCancelSpinLock(&oldIrql);
  2175. for ( pEntry = QueuedCompletionList.Flink;
  2176. pEntry != &QueuedCompletionList;
  2177. pEntry = pEntry->Flink ) {
  2178. pPendingIrp = CONTAINING_RECORD( pEntry, PENDING_IRP, Linkage);
  2179. if ((pQItem->OpCode == OP_ANY_CFINFO ||
  2180. pQItem->OpCode == pPendingIrp->QComp.OpCode)
  2181. &&
  2182. pPendingIrp->QComp.ClientHandle == (PVOID)pQItem->ClientHandle
  2183. &&
  2184. pPendingIrp->QComp.CfInfoHandle == (PVOID)pQItem->CfInfoHandle) {
  2185. //
  2186. // the queued item if for this file object
  2187. // and the OpCode match
  2188. // and it has the same CfInfo memory pointer
  2189. //
  2190. GpcRemoveEntryList(pEntry);
  2191. break;
  2192. } else {
  2193. pPendingIrp = NULL;
  2194. }
  2195. }
  2196. if (pPendingIrp) {
  2197. //
  2198. // get the status and free the queued completion item
  2199. //
  2200. DBGPRINT(IOCTL, ("CheckQueuedCompletion: found pPendingIrp=0x%X, Status=0x%X\n",
  2201. (ULONG_PTR)pPendingIrp, pPendingIrp->QComp.Status));
  2202. TRACE(IOCTL,
  2203. pPendingIrp->QComp.OpCode,
  2204. pPendingIrp->QComp.ClientHandle,
  2205. "CheckQueuedCompletion.Q:");
  2206. TRACE(IOCTL,
  2207. pPendingIrp->QComp.CfInfoHandle,
  2208. pPendingIrp->QComp.Status,
  2209. "CheckQueuedCompletion.Q:");
  2210. #if DBG
  2211. if (pQItem->OpCode != OP_ANY_CFINFO) {
  2212. ASSERT(pPendingIrp->QComp.OpCode == pQItem->OpCode);
  2213. ASSERT(pPendingIrp->QComp.ClientHandle == pQItem->ClientHandle);
  2214. }
  2215. #endif
  2216. Status = pPendingIrp->QComp.Status;
  2217. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  2218. } else {
  2219. DBGPRINT(IOCTL, ("CheckQueuedCompletion: pPendingIrp not found...PENDING\n"
  2220. ));
  2221. TRACE(IOCTL, 0, 0, "CheckQueuedCompletion.NopQ:");
  2222. GpcAllocFromLL(&pPendingIrp, &PendingIrpLL, PendingIrpTag);
  2223. if (pPendingIrp != NULL) {
  2224. //
  2225. // add the IRP on the pending CfInfo list
  2226. //
  2227. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2228. DBGPRINT(IOCTL, ("CheckQueuedCompletion: adding IRP=0x%X\n",
  2229. (ULONG_PTR)Irp ));
  2230. TRACE(IOCTL, Irp, irpStack, "CheckQueuedCompletion.Irp:");
  2231. pPendingIrp->Irp = Irp;
  2232. pPendingIrp->FileObject = irpStack->FileObject;
  2233. pPendingIrp->QComp.OpCode = pQItem->OpCode;
  2234. pPendingIrp->QComp.ClientHandle = pQItem->ClientHandle;
  2235. pPendingIrp->QComp.CfInfoHandle = pQItem->CfInfoHandle;
  2236. pPendingIrp->QComp.Status = pQItem->Status;
  2237. if (!Irp->Cancel) {
  2238. IoSetCancelRoutine(Irp, CancelPendingIrpCfInfo);
  2239. GpcInsertTailList(&PendingIrpCfInfoList, &(pPendingIrp->Linkage));
  2240. Status = STATUS_PENDING;
  2241. } else {
  2242. DBGPRINT(IOCTL, ("CheckQueuedCompletion: Status Cacelled: IRP=0x%X\n",
  2243. (ULONG_PTR)Irp ));
  2244. TRACE(IOCTL, Irp, irpStack, "CheckQueuedCompletion.Cancelled:");
  2245. GpcFreeToLL(pPendingIrp, &PendingIrpLL, PendingIrpTag);
  2246. Status = STATUS_CANCELLED;
  2247. }
  2248. } else {
  2249. Status = STATUS_INSUFFICIENT_RESOURCES;
  2250. }
  2251. }
  2252. IoReleaseCancelSpinLock(oldIrql);
  2253. return Status;
  2254. }
  2255. // Function : GpcValidateClientOwner
  2256. //
  2257. // Description:
  2258. // Validates that the user mode calling an irp owns the client in
  2259. // question.
  2260. //
  2261. //Arguments:
  2262. // GpcClientHandle: Object obtained from client handle.
  2263. // In effect pointer to CLIENT_BLOCK
  2264. //
  2265. //Returns:
  2266. // Returns GPC_STATUS_SUCCESS if the given client is owned by the file object
  2267. // Returns GPC_STATUS_INVALID_HANDLE otherwise
  2268. //
  2269. //Environment:
  2270. // Called to validate client ownership of CLIENT_BLOCK from the
  2271. // proxyGpc* functions . No locks held
  2272. //
  2273. NTSTATUS
  2274. GpcValidateClientOwner (
  2275. IN GPC_HANDLE GpcClientHandle,
  2276. IN PFILE_OBJECT pFile
  2277. )
  2278. {
  2279. PCLIENT_BLOCK pClient;
  2280. NTSTATUS Status = GPC_STATUS_SUCCESS;
  2281. pClient = (PCLIENT_BLOCK) GpcClientHandle;
  2282. NDIS_LOCK(&pClient->Lock);
  2283. if (pClient->pFileObject != pFile)
  2284. {
  2285. Status = GPC_STATUS_INVALID_HANDLE;
  2286. }
  2287. NDIS_UNLOCK(&pClient->Lock);
  2288. return Status;
  2289. }
  2290. // Function : GpcValidatePatternOwner
  2291. //
  2292. // Description:
  2293. // Validates that the user mode client owns the Pattern in
  2294. // question.
  2295. //
  2296. //Arguments:
  2297. // GpcClientHandle: Object obtained from client handle.
  2298. // In effect pointer to CLIENT_BLOCK
  2299. // GpcPatternHandle: Object Obtained from Pattern Handle
  2300. // In effect pointer to the PATTERN_BLOCK
  2301. //Returns:
  2302. // Returns GPC_STATUS_SUCCESS if the specified client owns the
  2303. // specified Pattern.
  2304. // Returns GPC_STATUS_ACCESS_DENIED otherwise
  2305. //
  2306. //Environment:
  2307. // Called to validate client ownership of PATTERN_BLOCK from the
  2308. // proxyGpc* functions .
  2309. //
  2310. NTSTATUS
  2311. GpcValidatePatternOwner (
  2312. IN GPC_HANDLE GpcClientHandle,
  2313. IN GPC_HANDLE GpcPatternHandle
  2314. )
  2315. {
  2316. PCLIENT_BLOCK pClient;
  2317. PPATTERN_BLOCK pPattern;
  2318. NTSTATUS Status = GPC_STATUS_SUCCESS;
  2319. pClient = (PCLIENT_BLOCK) GpcClientHandle;
  2320. pPattern = (PPATTERN_BLOCK)GpcPatternHandle;
  2321. if (pClient != pPattern->pClientBlock )
  2322. {
  2323. Status = GPC_STATUS_INVALID_HANDLE;
  2324. }
  2325. return Status;
  2326. }
  2327. // Function : GpcValidateCfinfoOwner
  2328. //
  2329. // Description:
  2330. // Validates that the user mode client owns the BLOB in
  2331. // question.
  2332. //
  2333. //Arguments:
  2334. // GpcClientHandle: Object obtained from client handle.
  2335. // In effect pointer to CLIENT_BLOCK
  2336. // GpcCfinfoHandle: Object Obtained from Pattern Handle
  2337. // In effect pointer to the PATTERN_BLOCK
  2338. //Returns:
  2339. // Returns GPC_STATUS_SUCCESS if the specified client owns the
  2340. // specified Cfinfo - BLOB_BLOCK.
  2341. // Returns GPC_STATUS_ACCESS_DENIED otherwise
  2342. //
  2343. //Environment:
  2344. // Called to validate client ownership of BLOB_BLOCK from the
  2345. // proxyGpc* functions .
  2346. //
  2347. NTSTATUS
  2348. GpcValidateCfinfoOwner (
  2349. IN GPC_HANDLE GpcClientHandle,
  2350. IN GPC_HANDLE GpcCfInfoHandle
  2351. )
  2352. {
  2353. PCLIENT_BLOCK pClient;
  2354. PBLOB_BLOCK pBlob;
  2355. NTSTATUS Status = GPC_STATUS_SUCCESS;
  2356. pClient = (PCLIENT_BLOCK) GpcClientHandle;
  2357. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  2358. if (pClient != pBlob->pOwnerClient)
  2359. {
  2360. Status = GPC_STATUS_INVALID_HANDLE;
  2361. }
  2362. return Status;
  2363. }
  2364. /* end ioctl.c */