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.

8471 lines
221 KiB

  1. /*++
  2. Copyright (c) 1989-1999 Microsoft Corporation
  3. Module Name:
  4. misc.c
  5. Abstract:
  6. This module contains the miscellaneous AFD routines.
  7. Author:
  8. David Treadwell (davidtr) 13-Nov-1992
  9. Revision History:
  10. Vadim Eydelman (vadime) 1998-1999 Misc changes
  11. --*/
  12. #include "afdp.h"
  13. #define TL_INSTANCE 0
  14. #include <ipexport.h>
  15. #include <tdiinfo.h>
  16. #include <tcpinfo.h>
  17. #include <ntddtcp.h>
  18. VOID
  19. AfdDoWork (
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN PVOID Context
  22. );
  23. NTSTATUS
  24. AfdRestartDeviceControl (
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp,
  27. IN PVOID Context
  28. );
  29. VOID
  30. AfdUnlockDriver (
  31. IN PVOID Context
  32. );
  33. BOOLEAN
  34. AfdCompareAddresses(
  35. IN PTRANSPORT_ADDRESS Address1,
  36. IN ULONG Address1Length,
  37. IN PTRANSPORT_ADDRESS Address2,
  38. IN ULONG Address2Length
  39. );
  40. NTSTATUS
  41. AfdCompleteTransportIoctl (
  42. IN PDEVICE_OBJECT DeviceObject,
  43. IN PIRP Irp,
  44. IN PVOID Context
  45. );
  46. NTSTATUS
  47. AfdCompleteNBTransportIoctl (
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp,
  50. IN PVOID Context
  51. );
  52. BOOLEAN
  53. AfdCleanupTransportIoctl (
  54. PAFD_ENDPOINT Endpoint,
  55. PAFD_REQUEST_CONTEXT RequestCtx
  56. );
  57. BOOLEAN
  58. AfdCleanupNBTransportIoctl (
  59. PAFD_ENDPOINT Endpoint,
  60. PAFD_REQUEST_CONTEXT RequestCtx
  61. );
  62. #ifdef _WIN64
  63. NTSTATUS
  64. AfdQueryHandles32 (
  65. IN PIRP Irp,
  66. IN PIO_STACK_LOCATION IrpSp
  67. );
  68. NTSTATUS
  69. AfdSetQos32(
  70. IN PIRP Irp,
  71. IN PIO_STACK_LOCATION IrpSp
  72. );
  73. NTSTATUS
  74. AfdGetQos32(
  75. IN PIRP Irp,
  76. IN PIO_STACK_LOCATION IrpSp
  77. );
  78. NTSTATUS
  79. AfdNoOperation32(
  80. IN PIRP Irp,
  81. IN PIO_STACK_LOCATION IrpSp
  82. );
  83. #endif
  84. VOID
  85. AfdLRListTimeout (
  86. IN PKDPC Dpc,
  87. IN PVOID DeferredContext,
  88. IN PVOID SystemArgument1,
  89. IN PVOID SystemArgument2
  90. );
  91. VOID
  92. AfdProcessLRList (
  93. PVOID Param
  94. );
  95. VOID
  96. AfdLRStartTimer (
  97. VOID
  98. );
  99. #ifdef ALLOC_PRAGMA
  100. #pragma alloc_text( PAGE, AfdCalcBufferArrayByteLength )
  101. #pragma alloc_text( PAGE, AfdCopyBufferArrayToBuffer )
  102. #pragma alloc_text( PAGE, AfdCopyBufferToBufferArray )
  103. #pragma alloc_text( PAGE, AfdCopyMdlChainToBufferArray )
  104. #pragma alloc_text( PAGEAFD, AfdMapMdlChain )
  105. #pragma alloc_text( PAGEAFD, AfdCopyMdlChainToMdlChain )
  106. #pragma alloc_text( PAGEAFD, AfdAdvanceMdlChain )
  107. #pragma alloc_text( PAGEAFD, AfdAllocateMdlChain )
  108. #pragma alloc_text( PAGE, AfdQueryHandles )
  109. #pragma alloc_text( PAGE, AfdGetInformation )
  110. #pragma alloc_text( PAGEAFD, AfdSetInformation )
  111. #pragma alloc_text( PAGE, AfdSetInLineMode )
  112. #pragma alloc_text( PAGE, AfdGetContext )
  113. #pragma alloc_text( PAGE, AfdGetRemoteAddress )
  114. #pragma alloc_text( PAGE, AfdSetContext )
  115. #pragma alloc_text( PAGE, AfdIssueDeviceControl )
  116. #pragma alloc_text( PAGE, AfdSetEventHandler )
  117. #pragma alloc_text( PAGE, AfdInsertNewEndpointInList )
  118. #pragma alloc_text( PAGE, AfdRemoveEndpointFromList )
  119. #pragma alloc_text( PAGE, AfdQueryProviderInfo )
  120. #pragma alloc_text( PAGE, AfdLockEndpointContext )
  121. #pragma alloc_text( PAGE, AfdUnlockEndpointContext )
  122. #pragma alloc_text( PAGEAFD, AfdCompleteIrpList )
  123. #pragma alloc_text( PAGEAFD, AfdErrorEventHandler )
  124. #pragma alloc_text( PAGEAFD, AfdErrorExEventHandler )
  125. //#pragma alloc_text( PAGEAFD, AfdRestartDeviceControl ) // can't ever be paged!
  126. #pragma alloc_text( PAGEAFD, AfdGetConnectData )
  127. #pragma alloc_text( PAGEAFD, AfdSetConnectData )
  128. #pragma alloc_text( PAGEAFD, AfdFreeConnectDataBuffers )
  129. #pragma alloc_text( PAGEAFD, AfdSaveReceivedConnectData )
  130. // The routines below can be called when no endpoints are in the list
  131. //#pragma alloc_text( PAGEAFD, AfdDoWork )
  132. //#pragma alloc_text( PAGEAFD, AfdQueueWorkItem )
  133. #pragma alloc_text( PAGEAFD, AfdGetWorkerByRoutine )
  134. #pragma alloc_text( PAGE, AfdProcessLRList)
  135. #pragma alloc_text( PAGEAFD, AfdLRListTimeout)
  136. #pragma alloc_text( PAGEAFD, AfdLRStartTimer)
  137. #pragma alloc_text( PAGEAFD, AfdLRListAddItem)
  138. // Re-enable paging of the routines below when
  139. // KeFlushQueuedDpcs is exported from kernel.
  140. //#pragma alloc_text( PAGEAFD, AfdTrimLookaside)
  141. //#pragma alloc_text( PAGEAFD, AfdCheckLookasideLists)
  142. #if DBG
  143. #pragma alloc_text( PAGEAFD, AfdRecordOutstandingIrpDebug )
  144. #endif
  145. #pragma alloc_text( PAGE, AfdExceptionFilter )
  146. #pragma alloc_text( PAGEAFD, AfdSetQos )
  147. #pragma alloc_text( PAGE, AfdGetQos )
  148. #pragma alloc_text( PAGE, AfdNoOperation )
  149. #pragma alloc_text (PAGE, AfdValidateStatus)
  150. #pragma alloc_text( PAGEAFD, AfdValidateGroup )
  151. #pragma alloc_text( PAGEAFD, AfdCompareAddresses )
  152. #pragma alloc_text( PAGEAFD, AfdGetUnacceptedConnectData )
  153. #pragma alloc_text( PAGE, AfdDoTransportIoctl )
  154. #pragma alloc_text( PAGEAFD, AfdCancelIrp )
  155. #ifdef _WIN64
  156. #pragma alloc_text( PAGEAFD, AfdAllocateMdlChain32 )
  157. #pragma alloc_text( PAGEAFD, AfdSetQos32 )
  158. #pragma alloc_text( PAGE, AfdGetQos32 )
  159. #pragma alloc_text( PAGE, AfdNoOperation32 )
  160. #endif
  161. #endif
  162. VOID
  163. AfdCompleteIrpList (
  164. IN PLIST_ENTRY IrpListHead,
  165. IN PAFD_ENDPOINT Endpoint,
  166. IN NTSTATUS Status,
  167. IN PAFD_IRP_CLEANUP_ROUTINE CleanupRoutine OPTIONAL
  168. )
  169. /*++
  170. Routine Description:
  171. Completes a list of IRPs with the specified status.
  172. Arguments:
  173. IrpListHead - the head of the list of IRPs to complete.
  174. Endpoint - an endpoint which lock which protects the list of IRPs.
  175. Status - the status to use for completing the IRPs.
  176. CleanupRoutine - a pointer to an optional IRP cleanup routine called
  177. before the IRP is completed.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. PLIST_ENTRY listEntry;
  183. PIRP irp;
  184. AFD_LOCK_QUEUE_HANDLE lockHandle;
  185. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  186. while ( !IsListEmpty( IrpListHead ) ) {
  187. //
  188. // Remove the first IRP from the list, get a pointer to
  189. // the IRP and reset the cancel routine in the IRP. The
  190. // IRP is no longer cancellable.
  191. //
  192. listEntry = RemoveHeadList( IrpListHead );
  193. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  194. if ( IoSetCancelRoutine( irp, NULL ) == NULL ) {
  195. //
  196. // This IRP is about to be canceled. Look for another in the
  197. // list. Set the Flink to NULL so the cancel routine knows
  198. // it is not on the list.
  199. //
  200. irp->Tail.Overlay.ListEntry.Flink = NULL;
  201. continue;
  202. }
  203. //
  204. // If we have a cleanup routine, call it.
  205. //
  206. if( CleanupRoutine != NULL ) {
  207. if (!(CleanupRoutine)( irp )) {
  208. //
  209. // Cleanup routine indicated that IRP should not
  210. // be completed.
  211. //
  212. continue;
  213. }
  214. }
  215. //
  216. // We must release the locks in order to actually
  217. // complete the IRP. It is OK to release these locks
  218. // because we don't maintain any absolute pointer into
  219. // the list; the loop termination condition is just
  220. // whether the list is completely empty.
  221. //
  222. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  223. //
  224. // Complete the IRP.
  225. //
  226. irp->IoStatus.Status = Status;
  227. irp->IoStatus.Information = 0;
  228. IoCompleteRequest( irp, AfdPriorityBoost );
  229. //
  230. // Reacquire the locks and continue completing IRPs.
  231. //
  232. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  233. }
  234. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  235. return;
  236. } // AfdCompleteIrpList
  237. NTSTATUS
  238. AfdErrorEventHandler (
  239. IN PVOID TdiEventContext,
  240. IN NTSTATUS Status
  241. )
  242. {
  243. PAFD_ENDPOINT endpoint = TdiEventContext;
  244. BOOLEAN result;
  245. CHECK_REFERENCE_ENDPOINT (endpoint, result);
  246. if (!result)
  247. return STATUS_SUCCESS;
  248. switch (Status) {
  249. case STATUS_PORT_UNREACHABLE:
  250. AfdErrorExEventHandler (TdiEventContext, Status, NULL);
  251. break;
  252. default:
  253. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  254. "AfdErrorEventHandler called for endpoint %p\n",
  255. endpoint ));
  256. }
  257. DEREFERENCE_ENDPOINT (endpoint);
  258. return STATUS_SUCCESS;
  259. }
  260. NTSTATUS
  261. AfdErrorExEventHandler (
  262. IN PVOID TdiEventContext,
  263. IN NTSTATUS Status,
  264. IN PVOID Context
  265. )
  266. {
  267. PAFD_ENDPOINT endpoint = TdiEventContext;
  268. BOOLEAN result;
  269. CHECK_REFERENCE_ENDPOINT (endpoint, result);
  270. if (!result)
  271. return STATUS_SUCCESS;
  272. switch (Status) {
  273. case STATUS_PORT_UNREACHABLE:
  274. //
  275. // UDP uses error ex handler to report ICMP rejects
  276. //
  277. if (IS_DGRAM_ENDPOINT (endpoint) &&
  278. !endpoint->Common.Datagram.DisablePUError) {
  279. AFD_LOCK_QUEUE_HANDLE lockHandle;
  280. PLIST_ENTRY listEntry;
  281. PIRP irp = NULL;
  282. PTRANSPORT_ADDRESS sourceAddress = Context;
  283. int sourceAddressLength;
  284. PAFD_BUFFER_TAG afdBuffer;
  285. if (sourceAddress!=NULL) {
  286. sourceAddressLength =
  287. FIELD_OFFSET(TRANSPORT_ADDRESS,
  288. Address[0].Address[sourceAddress->Address[0].AddressLength]);
  289. }
  290. else
  291. sourceAddressLength = 0;
  292. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  293. //
  294. // First try to fail any of the receive IRPs
  295. //
  296. while (!IsListEmpty (&endpoint->ReceiveDatagramIrpListHead)) {
  297. listEntry = RemoveHeadList( &endpoint->ReceiveDatagramIrpListHead );
  298. //
  299. // Get a pointer to the IRP and reset the cancel routine in
  300. // the IRP. The IRP is no longer cancellable.
  301. //
  302. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  303. if ( IoSetCancelRoutine( irp, NULL ) != NULL ) {
  304. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  305. irp->IoStatus.Status = Status;
  306. irp->IoStatus.Information = 0;
  307. AfdSetupReceiveDatagramIrp (irp, NULL, 0, NULL, 0,
  308. sourceAddress,
  309. sourceAddressLength,
  310. 0
  311. );
  312. IoCompleteRequest( irp, AfdPriorityBoost );
  313. goto Exit;
  314. }
  315. else {
  316. //
  317. // This IRP is about to be canceled. Look for another in the
  318. // list. Set the Flink to NULL so the cancel routine knows
  319. // it is not on the list.
  320. //
  321. irp->Tail.Overlay.ListEntry.Flink = NULL;
  322. irp = NULL;
  323. }
  324. }
  325. ASSERT (irp==NULL);
  326. //
  327. // See if there are any PEEK IRPs
  328. //
  329. while (!IsListEmpty (&endpoint->PeekDatagramIrpListHead)) {
  330. listEntry = RemoveHeadList( &endpoint->PeekDatagramIrpListHead );
  331. //
  332. // Get a pointer to the IRP and reset the cancel routine in
  333. // the IRP. The IRP is no longer cancellable.
  334. //
  335. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  336. if ( IoSetCancelRoutine( irp, NULL ) != NULL ) {
  337. break;
  338. }
  339. else {
  340. //
  341. // This IRP is about to be canceled. Look for another in the
  342. // list. Set the Flink to NULL so the cancel routine knows
  343. // it is not on the list.
  344. //
  345. irp->Tail.Overlay.ListEntry.Flink = NULL;
  346. irp = NULL;
  347. }
  348. }
  349. //
  350. // If we can buffer this indication, do it
  351. //
  352. if (endpoint->DgBufferredReceiveBytes <
  353. endpoint->Common.Datagram.MaxBufferredReceiveBytes &&
  354. (endpoint->DgBufferredReceiveBytes>0 ||
  355. (endpoint->DgBufferredReceiveCount*sizeof (AFD_BUFFER_TAG)) <
  356. endpoint->Common.Datagram.MaxBufferredReceiveBytes) ) {
  357. afdBuffer = AfdGetBufferTag( sourceAddressLength, endpoint->OwningProcess );
  358. if ( afdBuffer != NULL) {
  359. //
  360. // Save the status do distinguish this from
  361. // normal datagram IRP
  362. //
  363. afdBuffer->Status = Status;
  364. afdBuffer->DataLength = 0;
  365. afdBuffer->DatagramFlags = 0;
  366. afdBuffer->DataOffset = 0;
  367. RtlCopyMemory(
  368. afdBuffer->TdiInfo.RemoteAddress,
  369. sourceAddress,
  370. sourceAddressLength
  371. );
  372. afdBuffer->TdiInfo.RemoteAddressLength = sourceAddressLength;
  373. //
  374. // Place the buffer on this endpoint's list of bufferred datagrams
  375. // and update the counts of datagrams and datagram bytes on the
  376. // endpoint.
  377. //
  378. InsertTailList(
  379. &endpoint->ReceiveDatagramBufferListHead,
  380. &afdBuffer->BufferListEntry
  381. );
  382. endpoint->DgBufferredReceiveCount++;
  383. //
  384. // All done. Release the lock and tell the provider that we
  385. // took all the data.
  386. //
  387. AfdIndicateEventSelectEvent(
  388. endpoint,
  389. AFD_POLL_RECEIVE,
  390. STATUS_SUCCESS
  391. );
  392. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  393. //
  394. // Indicate that it is possible to receive on the endpoint now.
  395. //
  396. AfdIndicatePollEvent(
  397. endpoint,
  398. AFD_POLL_RECEIVE,
  399. STATUS_SUCCESS
  400. );
  401. }
  402. else {
  403. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  404. }
  405. }
  406. else {
  407. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  408. }
  409. //
  410. // If there was a peek IRP on the endpoint, complete it now.
  411. //
  412. if ( irp != NULL ) {
  413. irp->IoStatus.Status = Status;
  414. irp->IoStatus.Information = 0;
  415. AfdSetupReceiveDatagramIrp (irp, NULL, 0, NULL, 0,
  416. sourceAddress,
  417. sourceAddressLength,
  418. 0
  419. );
  420. IoCompleteRequest( irp, AfdPriorityBoost );
  421. }
  422. }
  423. break;
  424. }
  425. Exit:
  426. DEREFERENCE_ENDPOINT (endpoint);
  427. return STATUS_SUCCESS;
  428. } // AfdErrorEventHandler
  429. VOID
  430. AfdInsertNewEndpointInList (
  431. IN PAFD_ENDPOINT Endpoint
  432. )
  433. /*++
  434. Routine Description:
  435. Inserts a new endpoint in the global list of AFD endpoints. If this
  436. is the first endpoint, then this routine does various allocations to
  437. prepare AFD for usage.
  438. Arguments:
  439. Endpoint - the endpoint being added.
  440. Return Value:
  441. None.
  442. --*/
  443. {
  444. PAGED_CODE( );
  445. //
  446. // Acquire a lock which prevents other threads from performing this
  447. // operation.
  448. //
  449. //
  450. // Make sure the thread in which we execute cannot get
  451. // suspeneded in APC while we own the global resource.
  452. //
  453. KeEnterCriticalRegion ();
  454. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  455. InterlockedIncrement(
  456. &AfdEndpointsOpened
  457. );
  458. //
  459. // If the list of endpoints is empty, do some allocations.
  460. //
  461. if ( IsListEmpty( &AfdEndpointListHead ) ) {
  462. //
  463. // Tell MM to revert to normal paging semantics.
  464. //
  465. if (!AfdLoaded) {
  466. MmResetDriverPaging( DriverEntry );
  467. AfdLoaded = (PKEVENT)1;
  468. }
  469. //
  470. // Lock down the AFD section that cannot be pagable if any
  471. // sockets are open.
  472. //
  473. ASSERT( AfdDiscardableCodeHandle == NULL );
  474. AfdDiscardableCodeHandle = MmLockPagableCodeSection( AfdGetBuffer );
  475. ASSERT( AfdDiscardableCodeHandle != NULL );
  476. //
  477. // Add extra reference to afd device object so that the
  478. // driver cannot be unloaded while at least one endpoint
  479. // is in the list.
  480. //
  481. ObReferenceObject (AfdDeviceObject);
  482. //
  483. // Setup 30 sec timer to flush lookaside lists
  484. // if too many items are there for too long.
  485. //
  486. KeInitializeTimer (&AfdLookasideLists->Timer);
  487. KeInitializeDpc (&AfdLookasideLists->Dpc, AfdCheckLookasideLists, AfdLookasideLists);
  488. {
  489. LARGE_INTEGER dueTime;
  490. dueTime.QuadPart = -(30*1000*1000*10);
  491. KeSetTimerEx (&AfdLookasideLists->Timer,
  492. dueTime,
  493. 30*1000,
  494. &AfdLookasideLists->Dpc);
  495. }
  496. }
  497. ASSERT (AfdLoaded==(PKEVENT)1);
  498. //
  499. // Add the endpoint to the list(s).
  500. //
  501. InsertHeadList(
  502. &AfdEndpointListHead,
  503. &Endpoint->GlobalEndpointListEntry
  504. );
  505. if( Endpoint->GroupType == GroupTypeConstrained ) {
  506. InsertHeadList(
  507. &AfdConstrainedEndpointListHead,
  508. &Endpoint->ConstrainedEndpointListEntry
  509. );
  510. }
  511. //
  512. // Release the lock and return.
  513. //
  514. ExReleaseResourceLite( AfdResource );
  515. KeLeaveCriticalRegion ();
  516. return;
  517. } // AfdInsertNewEndpointInList
  518. VOID
  519. AfdRemoveEndpointFromList (
  520. IN PAFD_ENDPOINT Endpoint
  521. )
  522. /*++
  523. Routine Description:
  524. Removes a new endpoint from the global list of AFD endpoints. If
  525. this is the last endpoint in the list, then this routine does
  526. various deallocations to save resource utilization.
  527. Arguments:
  528. Endpoint - the endpoint being removed.
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. PAGED_CODE( );
  534. //
  535. // Acquire a lock which prevents other threads from performing this
  536. // operation.
  537. //
  538. //
  539. // Make sure the thread in which we execute cannot get
  540. // suspeneded in APC while we own the global resource.
  541. //
  542. KeEnterCriticalRegion ();
  543. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  544. InterlockedIncrement(
  545. &AfdEndpointsClosed
  546. );
  547. //
  548. // Remove the endpoint from the list(s).
  549. //
  550. RemoveEntryList(
  551. &Endpoint->GlobalEndpointListEntry
  552. );
  553. if( Endpoint->GroupType == GroupTypeConstrained ) {
  554. RemoveEntryList(
  555. &Endpoint->ConstrainedEndpointListEntry
  556. );
  557. }
  558. //
  559. // If the list of endpoints is now empty, do some deallocations.
  560. //
  561. if ( IsListEmpty( &AfdEndpointListHead ) ) {
  562. //
  563. // Stop the timer that scans lookaside lists.
  564. //
  565. KeCancelTimer (&AfdLookasideLists->Timer);
  566. //
  567. // Make sure DPC is completed since we may need to reinitialize
  568. // it after we exit this routine and new endpoint is created again.
  569. //
  570. KeRemoveQueueDpc (&AfdLookasideLists->Dpc);
  571. //
  572. // Make sure that DPC routine has actually completed before
  573. // unlocking code section where this routine resides.
  574. //
  575. // Not exported from kernel - so don't put the routine
  576. // into the discardable code section until it is.
  577. //
  578. // KeFlushQueuedDpcs ();
  579. //
  580. // Unlock the AFD section that can be pagable when no sockets
  581. // are open.
  582. //
  583. ASSERT( IsListEmpty( &AfdConstrainedEndpointListHead ) );
  584. ASSERT( AfdDiscardableCodeHandle != NULL );
  585. MmUnlockPagableImageSection( AfdDiscardableCodeHandle );
  586. AfdDiscardableCodeHandle = NULL;
  587. //
  588. // Queue off an executive worker thread to unlock AFD. We do
  589. // this using special hacks in the AFD worker thread code so
  590. // that we don't need to acuire a spin lock after the unlock.
  591. //
  592. AfdQueueWorkItem( AfdUnlockDriver, &AfdUnloadWorker );
  593. }
  594. //
  595. // Release the lock and return.
  596. //
  597. ExReleaseResourceLite( AfdResource );
  598. KeLeaveCriticalRegion ();
  599. return;
  600. } // AfdRemoveEndpointFromList
  601. VOID
  602. AfdUnlockDriver (
  603. IN PVOID Context
  604. )
  605. {
  606. //
  607. // Acquire a lock which prevents other threads from performing this
  608. // operation.
  609. //
  610. //
  611. // Make sure the thread in which we execute cannot get
  612. // suspeneded in APC while we own the global resource.
  613. //
  614. KeEnterCriticalRegion ();
  615. ExAcquireResourceExclusiveLite( AfdResource, TRUE );
  616. //
  617. // Test whether the endpoint list remains empty. If it is still
  618. // empty, we can proceed with unlocking the driver. If a new
  619. // endpoint has been placed on the list, then do not make AFD
  620. // pagable.
  621. //
  622. if ( IsListEmpty( &AfdEndpointListHead ) ) {
  623. //
  624. // Tell MM that it can page all of AFD as it desires.
  625. //
  626. if (AfdLoaded!=NULL && AfdLoaded!=(PKEVENT)1) {
  627. KeSetEvent (AfdLoaded, AfdPriorityBoost, FALSE);
  628. }
  629. else {
  630. MmPageEntireDriver( DriverEntry );
  631. }
  632. AfdLoaded = NULL;
  633. }
  634. ExReleaseResourceLite( AfdResource );
  635. KeLeaveCriticalRegion ();
  636. } // AfdUnlockDriver
  637. NTSTATUS
  638. AfdQueryHandles (
  639. IN PFILE_OBJECT FileObject,
  640. IN ULONG IoctlCode,
  641. IN KPROCESSOR_MODE RequestorMode,
  642. IN PVOID InputBuffer,
  643. IN ULONG InputBufferLength,
  644. IN PVOID OutputBuffer,
  645. IN ULONG OutputBufferLength,
  646. OUT PUINT_PTR Information
  647. )
  648. /*++
  649. Routine Description:
  650. Returns information about the TDI handles corresponding to an AFD
  651. endpoint. NULL is returned for either the connection handle or the
  652. address handle (or both) if the endpoint does not have that particular
  653. object.
  654. Arguments:
  655. Irp - Pointer to I/O request packet.
  656. IrpSp - pointer to the IO stack location to use for this request.
  657. Return Value:
  658. NTSTATUS -- Indicates whether the request was successfully queued.
  659. --*/
  660. {
  661. PAFD_ENDPOINT endpoint;
  662. PAFD_CONNECTION connection;
  663. AFD_HANDLE_INFO handleInfo;
  664. ULONG getHandleInfo;
  665. NTSTATUS status;
  666. PAGED_CODE( );
  667. //
  668. // Set up local pointers.
  669. //
  670. status = STATUS_SUCCESS;
  671. *Information = 0;
  672. endpoint = FileObject->FsContext;
  673. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  674. //
  675. // Make sure that the input and output buffers are large enough.
  676. //
  677. #ifdef _WIN64
  678. if (IoIs32bitProcess (NULL)) {
  679. if ( InputBufferLength < sizeof(getHandleInfo) ||
  680. OutputBufferLength < sizeof(AFD_HANDLE_INFO32) ) {
  681. return STATUS_BUFFER_TOO_SMALL;
  682. }
  683. }
  684. else
  685. #endif
  686. {
  687. if ( InputBufferLength < sizeof(getHandleInfo) ||
  688. OutputBufferLength < sizeof(handleInfo) ) {
  689. return STATUS_BUFFER_TOO_SMALL;
  690. }
  691. }
  692. try {
  693. //
  694. // Validate the input structure if it comes from the user mode
  695. // application
  696. //
  697. if (RequestorMode != KernelMode ) {
  698. ProbeForRead (InputBuffer,
  699. sizeof (getHandleInfo),
  700. PROBE_ALIGNMENT(ULONG));
  701. }
  702. //
  703. // Make local copies of the embeded pointer and parameters
  704. // that we will be using more than once in case malicios
  705. // application attempts to change them while we are
  706. // validating
  707. //
  708. getHandleInfo = *((PULONG)InputBuffer);
  709. } except( AFD_EXCEPTION_FILTER(&status) ) {
  710. return status;
  711. }
  712. //
  713. // If no handle information or invalid handle information was
  714. // requested, fail.
  715. //
  716. if ( (getHandleInfo &
  717. ~(AFD_QUERY_ADDRESS_HANDLE | AFD_QUERY_CONNECTION_HANDLE)) != 0 ||
  718. getHandleInfo == 0 ) {
  719. return STATUS_INVALID_PARAMETER;
  720. }
  721. //
  722. // Initialize the output buffer.
  723. //
  724. handleInfo.TdiAddressHandle = NULL;
  725. handleInfo.TdiConnectionHandle = NULL;
  726. //
  727. // If the caller requested a TDI address handle and we have an
  728. // address handle for this endpoint, dupe the address handle to the
  729. // user process.
  730. //
  731. if ( (getHandleInfo & AFD_QUERY_ADDRESS_HANDLE) != 0 &&
  732. (endpoint->State == AfdEndpointStateBound ||
  733. endpoint->State == AfdEndpointStateConnected) &&
  734. endpoint->AddressFileObject != NULL ) {
  735. // If transport does not support new TDI_SERVICE_FORCE_ACCESS_CHECK_FLAG
  736. // we get the maximum possible access for the handle so that helper
  737. // DLL can do what it wants with it. Of course this compromises the
  738. // security, but we can't enforce it without the transport cooperation.
  739. status = ObOpenObjectByPointer(
  740. endpoint->AddressFileObject,
  741. OBJ_CASE_INSENSITIVE,
  742. NULL,
  743. MAXIMUM_ALLOWED,
  744. *IoFileObjectType,
  745. (KPROCESSOR_MODE)((endpoint->TdiServiceFlags&TDI_SERVICE_FORCE_ACCESS_CHECK)
  746. ? RequestorMode
  747. : KernelMode),
  748. &handleInfo.TdiAddressHandle
  749. );
  750. if ( !NT_SUCCESS(status) ) {
  751. return status;
  752. }
  753. }
  754. //
  755. // If the caller requested a TDI connection handle and we have a
  756. // connection handle for this endpoint, dupe the connection handle
  757. // to the user process. Note that we can have a connection and
  758. // TDI handle when endpoint is in process of being connected.
  759. // We should not return the connection handle until enpoint is
  760. // fully connected or it may go away while we are trying to
  761. // reference it if connection fails (bug 93096)
  762. //
  763. if ( (getHandleInfo & AFD_QUERY_CONNECTION_HANDLE) != 0 &&
  764. (endpoint->Type & AfdBlockTypeVcConnecting) == AfdBlockTypeVcConnecting &&
  765. endpoint->State == AfdEndpointStateConnected &&
  766. ((connection=AfdGetConnectionReferenceFromEndpoint (endpoint))!=NULL)) {
  767. ASSERT( connection->Type == AfdBlockTypeConnection );
  768. ASSERT( connection->FileObject != NULL );
  769. // If transport does not support new TDI_SERVICE_FORCE_ACCESS_CHECK_FLAG
  770. // we get the maximum possible access for the handle so that helper
  771. // DLL can do what it wants with it. Of course this compromises the
  772. // security, but we can't enforce it without the transport cooperation.
  773. status = ObOpenObjectByPointer(
  774. connection->FileObject,
  775. OBJ_CASE_INSENSITIVE,
  776. NULL,
  777. MAXIMUM_ALLOWED,
  778. *IoFileObjectType,
  779. (KPROCESSOR_MODE)((endpoint->TdiServiceFlags & TDI_SERVICE_FORCE_ACCESS_CHECK)
  780. ? RequestorMode
  781. : KernelMode),
  782. &handleInfo.TdiConnectionHandle
  783. );
  784. DEREFERENCE_CONNECTION (connection);
  785. if ( !NT_SUCCESS(status) ) {
  786. if ( handleInfo.TdiAddressHandle != NULL ) {
  787. ZwClose( handleInfo.TdiAddressHandle );
  788. }
  789. return status;
  790. }
  791. }
  792. try {
  793. #ifdef _WIN64
  794. if (IoIs32bitProcess (NULL)) {
  795. if (RequestorMode!=KernelMode) {
  796. ProbeForWrite (OutputBuffer,
  797. sizeof (AFD_HANDLE_INFO32),
  798. PROBE_ALIGNMENT32 (AFD_HANDLE_INFO32));
  799. }
  800. ((PAFD_HANDLE_INFO32)OutputBuffer)->TdiAddressHandle =
  801. (VOID * POINTER_32)HandleToUlong(handleInfo.TdiAddressHandle);
  802. ((PAFD_HANDLE_INFO32)OutputBuffer)->TdiConnectionHandle =
  803. (VOID * POINTER_32)HandleToUlong(handleInfo.TdiConnectionHandle);
  804. *Information = sizeof (AFD_HANDLE_INFO32);
  805. }
  806. else
  807. #endif
  808. {
  809. if (RequestorMode!=KernelMode) {
  810. ProbeForWrite (OutputBuffer,
  811. sizeof (handleInfo),
  812. PROBE_ALIGNMENT (AFD_HANDLE_INFO));
  813. }
  814. *((PAFD_HANDLE_INFO)OutputBuffer) = handleInfo;
  815. *Information = sizeof (handleInfo);
  816. }
  817. } except( AFD_EXCEPTION_FILTER(&status) ) {
  818. if ( handleInfo.TdiAddressHandle != NULL ) {
  819. ZwClose( handleInfo.TdiAddressHandle );
  820. }
  821. if ( handleInfo.TdiConnectionHandle != NULL ) {
  822. ZwClose( handleInfo.TdiConnectionHandle );
  823. }
  824. return status;
  825. }
  826. return STATUS_SUCCESS;
  827. } // AfdQueryHandles
  828. NTSTATUS
  829. AfdGetInformation (
  830. IN PFILE_OBJECT FileObject,
  831. IN ULONG IoctlCode,
  832. IN KPROCESSOR_MODE RequestorMode,
  833. IN PVOID InputBuffer,
  834. IN ULONG InputBufferLength,
  835. IN PVOID OutputBuffer,
  836. IN ULONG OutputBufferLength,
  837. OUT PUINT_PTR Information
  838. )
  839. /*++
  840. Routine Description:
  841. Gets information in the endpoint.
  842. Arguments:
  843. Irp - Pointer to I/O request packet.
  844. IrpSp - pointer to the IO stack location to use for this request.
  845. Return Value:
  846. NTSTATUS -- Indicates whether the request was successfully queued.
  847. --*/
  848. {
  849. PAFD_ENDPOINT endpoint;
  850. PAFD_CONNECTION connection;
  851. AFD_INFORMATION afdInfo;
  852. NTSTATUS status;
  853. LONGLONG currentTime;
  854. LONGLONG connectTime;
  855. PAGED_CODE( );
  856. //
  857. // Set up local pointers.
  858. //
  859. status = STATUS_SUCCESS;
  860. *Information = 0;
  861. endpoint = FileObject->FsContext;
  862. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  863. if (endpoint->Type==AfdBlockTypeHelper ||
  864. endpoint->Type==AfdBlockTypeSanHelper)
  865. return STATUS_INVALID_PARAMETER;
  866. //
  867. // Make sure that the input and output buffers are large enough.
  868. //
  869. #ifdef _WIN64
  870. {
  871. C_ASSERT (sizeof (AFD_INFORMATION)==sizeof (AFD_INFORMATION32));
  872. }
  873. #endif
  874. if ( InputBufferLength < sizeof(afdInfo.InformationType) ||
  875. OutputBufferLength < sizeof(afdInfo) ) {
  876. return STATUS_BUFFER_TOO_SMALL;
  877. }
  878. try {
  879. #ifdef _WIN64
  880. if (IoIs32bitProcess (NULL)) {
  881. //
  882. // Validate the input structure if it comes from the user mode
  883. // application
  884. //
  885. if (RequestorMode != KernelMode ) {
  886. ProbeForRead (InputBuffer,
  887. sizeof (InputBufferLength),
  888. PROBE_ALIGNMENT32(AFD_INFORMATION32));
  889. }
  890. //
  891. // Make local copies of the embeded pointer and parameters
  892. // that we will be using more than once in case malicios
  893. // application attempts to change them while we are
  894. // validating
  895. //
  896. afdInfo.InformationType = ((PAFD_INFORMATION32)InputBuffer)->InformationType;
  897. }
  898. else
  899. #endif _WIN64
  900. {
  901. //
  902. // Validate the input structure if it comes from the user mode
  903. // application
  904. //
  905. if (RequestorMode != KernelMode ) {
  906. ProbeForRead (InputBuffer,
  907. sizeof (InputBufferLength),
  908. PROBE_ALIGNMENT(AFD_INFORMATION));
  909. }
  910. //
  911. // Make local copies of the embeded pointer and parameters
  912. // that we will be using more than once in case malicios
  913. // application attempts to change them while we are
  914. // validating
  915. //
  916. afdInfo.InformationType = ((PAFD_INFORMATION)InputBuffer)->InformationType;
  917. }
  918. } except( AFD_EXCEPTION_FILTER(&status) ) {
  919. return status;
  920. }
  921. //
  922. // Set up appropriate information in the endpoint.
  923. //
  924. switch ( afdInfo.InformationType ) {
  925. case AFD_MAX_PATH_SEND_SIZE:
  926. if (InputBufferLength>sizeof (afdInfo) &&
  927. (endpoint->State==AfdEndpointStateBound || endpoint->State==AfdEndpointStateConnected)) {
  928. TDI_REQUEST_KERNEL_QUERY_INFORMATION kernelQueryInfo;
  929. TDI_CONNECTION_INFORMATION connectionInfo;
  930. PMDL mdl;
  931. InputBuffer = (PUCHAR)InputBuffer+sizeof (afdInfo);
  932. InputBufferLength -= sizeof (afdInfo);
  933. mdl = IoAllocateMdl(
  934. InputBuffer, // VirtualAddress
  935. InputBufferLength, // Length
  936. FALSE, // SecondaryBuffer
  937. TRUE, // ChargeQuota
  938. NULL // Irp
  939. );
  940. if (mdl!=NULL) {
  941. try {
  942. MmProbeAndLockPages(
  943. mdl, // MemoryDescriptorList
  944. RequestorMode, // AccessMode
  945. IoWriteAccess // Operation
  946. );
  947. status = STATUS_SUCCESS;
  948. }
  949. except (AFD_EXCEPTION_FILTER (&status)) {
  950. }
  951. if (NT_SUCCESS (status)) {
  952. connectionInfo.RemoteAddress = MmGetSystemAddressForMdlSafe (mdl, LowPagePriority);
  953. if (connectionInfo.RemoteAddress!=NULL) {
  954. connectionInfo.RemoteAddressLength = InputBufferLength;
  955. //
  956. // Set up a query to the TDI provider to obtain the largest
  957. // datagram that can be sent to a particular address.
  958. //
  959. kernelQueryInfo.QueryType = TDI_QUERY_MAX_DATAGRAM_INFO;
  960. kernelQueryInfo.RequestConnectionInformation = &connectionInfo;
  961. connectionInfo.UserDataLength = 0;
  962. connectionInfo.UserData = NULL;
  963. connectionInfo.OptionsLength = 0;
  964. connectionInfo.Options = NULL;
  965. //
  966. // Ask the TDI provider for the information.
  967. //
  968. status = AfdIssueDeviceControl(
  969. endpoint->AddressFileObject,
  970. &kernelQueryInfo,
  971. sizeof(kernelQueryInfo),
  972. &afdInfo.Information.Ulong,
  973. sizeof(afdInfo.Information.Ulong),
  974. TDI_QUERY_INFORMATION
  975. );
  976. }
  977. else
  978. status = STATUS_INSUFFICIENT_RESOURCES;
  979. MmUnlockPages (mdl);
  980. }
  981. IoFreeMdl (mdl);
  982. }
  983. else
  984. status = STATUS_INSUFFICIENT_RESOURCES;
  985. //
  986. // If the request succeeds, use this information. Otherwise,
  987. // fall through and use the transport's global information.
  988. // This is done because not all transports support this
  989. // particular TDI request, and for those which do not the
  990. // global information is a reasonable approximation.
  991. //
  992. if ( NT_SUCCESS(status) ) {
  993. break;
  994. }
  995. }
  996. case AFD_MAX_SEND_SIZE:
  997. {
  998. //
  999. // With PnP some provider info fields can change over time.
  1000. // so we query them each time we are asked.
  1001. //
  1002. TDI_PROVIDER_INFO providerInfo;
  1003. status = AfdQueryProviderInfo (
  1004. &endpoint->TransportInfo->TransportDeviceName,
  1005. &providerInfo);
  1006. if (NT_SUCCESS (status)) {
  1007. //
  1008. // Return the MaxSendSize or MaxDatagramSendSize from the
  1009. // TDI_PROVIDER_INFO based on whether or not this is a datagram
  1010. // endpoint.
  1011. //
  1012. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  1013. afdInfo.Information.Ulong = providerInfo.MaxDatagramSize;
  1014. } else {
  1015. afdInfo.Information.Ulong = providerInfo.MaxSendSize;
  1016. }
  1017. }
  1018. }
  1019. break;
  1020. case AFD_SENDS_PENDING:
  1021. //
  1022. // If this is an endpoint on a bufferring transport, no sends
  1023. // are pending in AFD. If it is on a nonbufferring transport,
  1024. // return the count of sends pended in AFD.
  1025. //
  1026. if ( IS_TDI_BUFFERRING(endpoint) ||
  1027. (endpoint->Type & AfdBlockTypeVcConnecting) != AfdBlockTypeVcConnecting ||
  1028. endpoint->State != AfdEndpointStateConnected ||
  1029. ((connection=AfdGetConnectionReferenceFromEndpoint (endpoint))==NULL)) {
  1030. afdInfo.Information.Ulong = 0;
  1031. } else {
  1032. afdInfo.Information.Ulong = connection->VcBufferredSendCount;
  1033. DEREFERENCE_CONNECTION (connection);
  1034. }
  1035. break;
  1036. case AFD_RECEIVE_WINDOW_SIZE:
  1037. //
  1038. // Return the default receive window.
  1039. //
  1040. afdInfo.Information.Ulong = AfdReceiveWindowSize;
  1041. break;
  1042. case AFD_SEND_WINDOW_SIZE:
  1043. //
  1044. // Return the default send window.
  1045. //
  1046. afdInfo.Information.Ulong = AfdSendWindowSize;
  1047. break;
  1048. case AFD_CONNECT_TIME:
  1049. //
  1050. // If the endpoint is not yet connected, return -1. Otherwise,
  1051. // calculate the number of seconds that the connection has been
  1052. // active.
  1053. //
  1054. if ( endpoint->State != AfdEndpointStateConnected ||
  1055. IS_DGRAM_ENDPOINT (endpoint) ||
  1056. (connection=AfdGetConnectionReferenceFromEndpoint( endpoint ))==NULL) {
  1057. afdInfo.Information.Ulong = 0xFFFFFFFF;
  1058. } else {
  1059. ASSERT( connection->Type == AfdBlockTypeConnection );
  1060. //
  1061. // Calculate how long the connection has been active by
  1062. // subtracting the time at which the connection started from
  1063. // the current time. Note that we convert the units of the
  1064. // time value from 100s of nanoseconds to seconds.
  1065. //
  1066. currentTime = KeQueryInterruptTime ();
  1067. connectTime = (currentTime - connection->ConnectTime);
  1068. connectTime /= 10*1000*1000;
  1069. //
  1070. // We can safely convert this to a ULONG because it takes
  1071. // 127 years to overflow a ULONG counting seconds. The
  1072. // bizarre conversion to a LARGE_INTEGER is required to
  1073. // prevent the compiler from optimizing out the full 64-bit
  1074. // division above. Without this, the compiler would do only
  1075. // a 32-bit division and lose some information.
  1076. //
  1077. //afdInfo->Information.Ulong = (ULONG)connectTime;
  1078. afdInfo.Information.Ulong = ((PLARGE_INTEGER)&connectTime)->LowPart;
  1079. DEREFERENCE_CONNECTION (connection);
  1080. }
  1081. break;
  1082. case AFD_GROUP_ID_AND_TYPE : {
  1083. PAFD_GROUP_INFO groupInfo;
  1084. groupInfo = (PAFD_GROUP_INFO)&afdInfo.Information.LargeInteger;
  1085. //
  1086. // Return the endpoint's group ID and group type.
  1087. //
  1088. groupInfo->GroupID = endpoint->GroupID;
  1089. groupInfo->GroupType = endpoint->GroupType;
  1090. }
  1091. break;
  1092. default:
  1093. return STATUS_INVALID_PARAMETER;
  1094. }
  1095. try {
  1096. #ifdef _WIN64
  1097. if (IoIs32bitProcess (NULL)) {
  1098. //
  1099. // Validate the input structure if it comes from the user mode
  1100. // application
  1101. //
  1102. if (RequestorMode != KernelMode ) {
  1103. ProbeForWrite (OutputBuffer,
  1104. sizeof (afdInfo),
  1105. PROBE_ALIGNMENT32(AFD_INFORMATION32));
  1106. }
  1107. //
  1108. // Copy parameters back to application's memory
  1109. //
  1110. RtlMoveMemory(InputBuffer,
  1111. &afdInfo,
  1112. sizeof (afdInfo));
  1113. }
  1114. else
  1115. #endif _WIN64
  1116. {
  1117. //
  1118. // Validate the output structure if it comes from the user mode
  1119. // application
  1120. //
  1121. if (RequestorMode != KernelMode ) {
  1122. ProbeForWrite (OutputBuffer,
  1123. sizeof (afdInfo),
  1124. PROBE_ALIGNMENT (AFD_INFORMATION));
  1125. }
  1126. //
  1127. // Copy parameters back to application's memory
  1128. //
  1129. *((PAFD_INFORMATION)OutputBuffer) = afdInfo;
  1130. }
  1131. } except( AFD_EXCEPTION_FILTER(&status) ) {
  1132. return status;
  1133. }
  1134. *Information = sizeof(afdInfo);
  1135. return STATUS_SUCCESS;
  1136. } // AfdGetInformation
  1137. NTSTATUS
  1138. AfdSetInformation (
  1139. IN PFILE_OBJECT FileObject,
  1140. IN ULONG IoctlCode,
  1141. IN KPROCESSOR_MODE RequestorMode,
  1142. IN PVOID InputBuffer,
  1143. IN ULONG InputBufferLength,
  1144. IN PVOID OutputBuffer,
  1145. IN ULONG OutputBufferLength,
  1146. OUT PUINT_PTR Information
  1147. )
  1148. /*++
  1149. Routine Description:
  1150. Sets information in the endpoint.
  1151. Arguments:
  1152. Irp - Pointer to I/O request packet.
  1153. IrpSp - pointer to the IO stack location to use for this request.
  1154. Return Value:
  1155. NTSTATUS -- Indicates whether the request was successfully queued.
  1156. --*/
  1157. {
  1158. PAFD_ENDPOINT endpoint;
  1159. PAFD_CONNECTION connection;
  1160. AFD_INFORMATION afdInfo;
  1161. NTSTATUS status;
  1162. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1163. //
  1164. // Nothing to return.
  1165. //
  1166. *Information = 0;
  1167. //
  1168. // Initialize locals for cleanup.
  1169. //
  1170. connection = NULL;
  1171. status = STATUS_SUCCESS;
  1172. //
  1173. // Set up local pointers.
  1174. //
  1175. endpoint = FileObject->FsContext;
  1176. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1177. if (endpoint->Type==AfdBlockTypeHelper ||
  1178. endpoint->Type==AfdBlockTypeSanHelper)
  1179. return STATUS_INVALID_PARAMETER;
  1180. //
  1181. // Make sure that the input buffer is large enough.
  1182. //
  1183. #ifdef _WIN64
  1184. {
  1185. C_ASSERT (sizeof (AFD_INFORMATION)==sizeof (AFD_INFORMATION32));
  1186. }
  1187. #endif
  1188. if ( InputBufferLength < sizeof(afdInfo) ) {
  1189. return STATUS_BUFFER_TOO_SMALL;
  1190. }
  1191. try {
  1192. #ifdef _WIN64
  1193. if (IoIs32bitProcess (NULL)) {
  1194. //
  1195. // Validate the input structure if it comes from the user mode
  1196. // application
  1197. //
  1198. if (RequestorMode != KernelMode ) {
  1199. ProbeForRead (InputBuffer,
  1200. sizeof (InputBufferLength),
  1201. PROBE_ALIGNMENT32(AFD_INFORMATION32));
  1202. }
  1203. //
  1204. // Make local copies of the embeded pointer and parameters
  1205. // that we will be using more than once in case malicios
  1206. // application attempts to change them while we are
  1207. // validating
  1208. //
  1209. RtlMoveMemory (&afdInfo, InputBuffer, sizeof (afdInfo));
  1210. }
  1211. else
  1212. #endif _WIN64
  1213. {
  1214. //
  1215. // Validate the input structure if it comes from the user mode
  1216. // application
  1217. //
  1218. if (RequestorMode != KernelMode ) {
  1219. ProbeForRead (InputBuffer,
  1220. sizeof (afdInfo),
  1221. PROBE_ALIGNMENT(AFD_INFORMATION));
  1222. }
  1223. //
  1224. // Make local copies of the embeded pointer and parameters
  1225. // that we will be using more than once in case malicios
  1226. // application attempts to change them while we are
  1227. // validating
  1228. //
  1229. afdInfo = *((PAFD_INFORMATION)InputBuffer);
  1230. }
  1231. } except( AFD_EXCEPTION_FILTER(&status) ) {
  1232. return status;
  1233. }
  1234. //
  1235. // Set up appropriate information in the endpoint.
  1236. //
  1237. switch ( afdInfo.InformationType ) {
  1238. case AFD_NONBLOCKING_MODE:
  1239. //
  1240. // Set the blocking mode of the endpoint. If TRUE, send and receive
  1241. // calls on the endpoint will fail if they cannot be completed
  1242. // immediately.
  1243. //
  1244. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1245. endpoint->NonBlocking = (afdInfo.Information.Boolean!=FALSE);
  1246. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1247. break;
  1248. case AFD_CIRCULAR_QUEUEING:
  1249. //
  1250. // Enables circular queuing on the endpoint.
  1251. //
  1252. if( !IS_DGRAM_ENDPOINT( endpoint ) ) {
  1253. status = STATUS_INVALID_PARAMETER;
  1254. goto Cleanup;
  1255. }
  1256. endpoint->Common.Datagram.CircularQueueing = (afdInfo.Information.Boolean!=FALSE);
  1257. break;
  1258. case AFD_REPORT_PORT_UNREACHABLE:
  1259. //
  1260. // Enables reporting PORT_UNREACHABLE to the app.
  1261. //
  1262. if( !IS_DGRAM_ENDPOINT( endpoint ) ) {
  1263. status = STATUS_INVALID_PARAMETER;
  1264. goto Cleanup;
  1265. }
  1266. endpoint->Common.Datagram.DisablePUError = (afdInfo.Information.Boolean==FALSE);
  1267. break;
  1268. case AFD_INLINE_MODE:
  1269. //
  1270. // Set the inline mode of the endpoint. If TRUE, a receive for
  1271. // normal data will be completed with either normal data or
  1272. // expedited data. If the endpoint is connected, we need to
  1273. // tell the TDI provider that the endpoint is inline so that it
  1274. // delivers data to us in order. If the endpoint is not yet
  1275. // connected, then we will set the inline mode when we create
  1276. // the TDI connection object.
  1277. //
  1278. if ( (endpoint->Type & AfdBlockTypeVcConnecting) == AfdBlockTypeVcConnecting ) {
  1279. connection = AfdGetConnectionReferenceFromEndpoint( endpoint );
  1280. if (connection!=NULL) {
  1281. status = AfdSetInLineMode(
  1282. connection,
  1283. afdInfo.Information.Boolean
  1284. );
  1285. if ( !NT_SUCCESS(status) ) {
  1286. goto Cleanup;
  1287. }
  1288. }
  1289. }
  1290. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1291. endpoint->InLine = (afdInfo.Information.Boolean!=FALSE);
  1292. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1293. break;
  1294. case AFD_RECEIVE_WINDOW_SIZE:
  1295. case AFD_SEND_WINDOW_SIZE: {
  1296. PCLONG maxBytes;
  1297. #ifdef AFDDBG_QUOTA
  1298. PVOID chargeBlock;
  1299. PSZ chargeType;
  1300. #endif
  1301. //
  1302. // First determine where the appropriate limits are stored in the
  1303. // connection or endpoint. We do this so that we can use common
  1304. // code to charge quota and set the new counters.
  1305. //
  1306. if ( (endpoint->Type & AfdBlockTypeVcConnecting) == AfdBlockTypeVcConnecting &&
  1307. endpoint->State == AfdEndpointStateConnected &&
  1308. ((connection = AfdGetConnectionReferenceFromEndpoint (endpoint))!=NULL) ) {
  1309. if ( afdInfo.InformationType == AFD_SEND_WINDOW_SIZE ) {
  1310. maxBytes = &connection->MaxBufferredSendBytes;
  1311. } else {
  1312. maxBytes = &connection->MaxBufferredReceiveBytes;
  1313. }
  1314. #ifdef AFDDBG_QUOTA
  1315. chargeBlock = connection;
  1316. chargeType = "SetInfo vcnb";
  1317. #endif
  1318. } else if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  1319. if ( afdInfo.InformationType == AFD_SEND_WINDOW_SIZE ) {
  1320. maxBytes = &endpoint->Common.Datagram.MaxBufferredSendBytes;
  1321. } else {
  1322. maxBytes = &endpoint->Common.Datagram.MaxBufferredReceiveBytes;
  1323. }
  1324. #ifdef AFDDBG_QUOTA
  1325. chargeBlock = endpoint;
  1326. chargeType = "SetInfo dgrm";
  1327. #endif
  1328. } else if (IS_SAN_ENDPOINT (endpoint) ) {
  1329. status = STATUS_SUCCESS;
  1330. goto Cleanup;
  1331. }
  1332. else {
  1333. status = STATUS_INVALID_PARAMETER;
  1334. goto Cleanup;
  1335. }
  1336. //
  1337. // Make sure that we always allow at least one message to be
  1338. // bufferred on an endpoint.
  1339. //
  1340. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  1341. if ( afdInfo.Information.Ulong == 0 ) {
  1342. //
  1343. // Don't allow the max receive bytes to go to zero, but
  1344. // max send bytes IS allowed to go to zero because it has
  1345. // special meaning: specifically, do not buffer sends.
  1346. //
  1347. if ( afdInfo.InformationType == AFD_RECEIVE_WINDOW_SIZE ) {
  1348. afdInfo.Information.Ulong = 1;
  1349. }
  1350. else {
  1351. ASSERT (afdInfo.InformationType == AFD_SEND_WINDOW_SIZE);
  1352. endpoint->DisableFastIoSend = TRUE;
  1353. }
  1354. }
  1355. else {
  1356. if( afdInfo.InformationType == AFD_SEND_WINDOW_SIZE ) {
  1357. endpoint->DisableFastIoSend = FALSE;
  1358. }
  1359. }
  1360. //
  1361. // Set up the new information in the AFD internal structure.
  1362. //
  1363. *maxBytes = (CLONG)afdInfo.Information.Ulong;
  1364. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  1365. break;
  1366. }
  1367. default:
  1368. status = STATUS_INVALID_PARAMETER;
  1369. }
  1370. Cleanup:
  1371. if (connection!=NULL) {
  1372. DEREFERENCE_CONNECTION (connection);
  1373. }
  1374. return status;
  1375. } // AfdSetInformation
  1376. NTSTATUS
  1377. AfdSetInLineMode (
  1378. IN PAFD_CONNECTION Connection,
  1379. IN BOOLEAN InLine
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. Sets a connection to be in inline mode. In inline mode, urgent data
  1384. is delivered in the order in which it is received. We must tell the
  1385. TDI provider about this so that it indicates data in the proper
  1386. order.
  1387. Arguments:
  1388. Connection - the AFD connection to set as inline.
  1389. InLine - TRUE to enable inline mode, FALSE to disable inline mode.
  1390. Return Value:
  1391. NTSTATUS -- Indicates whether the request was successfully
  1392. performed.
  1393. --*/
  1394. {
  1395. //
  1396. // Since TCP does not implement this correctly, do everything in AFD!!!
  1397. // Background:
  1398. // When this options is enabled, TCP indicates all the data as normal
  1399. // data, so we end up mixing it together which is against the spec.
  1400. // Also, since TCP stops reporting expedited data, SIOATMARK fails
  1401. // to report presence of OOB data altogether.
  1402. // When handling OOB data completely inside AFD we can only run into
  1403. // one problem: if AFD runs out of its receive buffer for the socket
  1404. // and refuses to accept more data from TCP so that TCP buffers it
  1405. // within itself, any OOB data arriving at this point can be indicated
  1406. // out of order (not inline).
  1407. //
  1408. // Well, this appears to be even worse. Some apps (SQL) send more than
  1409. // one byte of OOB data, TCP can only send one, so it sends everything
  1410. // but the last byte as normal and the last one as OOB. It then turns
  1411. // around and indicates the OOB (last byte) first which breaks the
  1412. // ordering required by OOBINLINE.
  1413. // In the end, we are broken one way or the other, so keep the things
  1414. // the way they were for number of years and wait for TCP to fix.
  1415. NTSTATUS status;
  1416. PTCP_REQUEST_SET_INFORMATION_EX setInfoEx;
  1417. TCPSocketOption *option;
  1418. UCHAR buffer[sizeof(*setInfoEx) + sizeof(*option)];
  1419. IO_STATUS_BLOCK ioStatusBlock;
  1420. KEVENT event;
  1421. PIRP irp;
  1422. PIO_STACK_LOCATION irpSp;
  1423. PAGED_CODE( );
  1424. //
  1425. // Initialize the TDI information buffers.
  1426. //
  1427. setInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)buffer;
  1428. setInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
  1429. setInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  1430. setInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  1431. setInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
  1432. setInfoEx->ID.toi_id = TCP_SOCKET_OOBINLINE;
  1433. setInfoEx->BufferSize = sizeof(*option);
  1434. option = (TCPSocketOption *)&setInfoEx->Buffer;
  1435. option->tso_value = InLine;
  1436. //
  1437. // Initialize the kernel event that will signal I/O completion.
  1438. //
  1439. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  1440. //
  1441. // Build TDI set information IRP.
  1442. //
  1443. irp = IoBuildDeviceIoControlRequest (
  1444. IOCTL_TCP_SET_INFORMATION_EX,
  1445. Connection->DeviceObject,
  1446. setInfoEx,
  1447. sizeof(*setInfoEx) + setInfoEx->BufferSize,
  1448. NULL,
  1449. 0,
  1450. FALSE, // InternalDeviceIoControl
  1451. &event,
  1452. &ioStatusBlock);
  1453. if (irp==NULL) {
  1454. return STATUS_INSUFFICIENT_RESOURCES;
  1455. }
  1456. irpSp = IoGetNextIrpStackLocation (irp);
  1457. irpSp->FileObject = Connection->FileObject;
  1458. //
  1459. // Call the driver.
  1460. //
  1461. status = IoCallDriver (Connection->DeviceObject, irp);
  1462. //
  1463. // Must be at below APC level or this IRP will never get fully completed.
  1464. //
  1465. ASSERT (KeGetCurrentIrql ()<APC_LEVEL);
  1466. //
  1467. // If necessary, wait for the I/O to complete.
  1468. //
  1469. if ( status == STATUS_PENDING ) {
  1470. status = KeWaitForSingleObject( (PVOID)&event, Executive, KernelMode, FALSE, NULL );
  1471. ASSERT (status==STATUS_SUCCESS);
  1472. }
  1473. else {
  1474. //
  1475. // The IRP must have been completed then and event set.
  1476. //
  1477. if (NT_ERROR (status) || KeReadStateEvent (&event))
  1478. ;
  1479. else {
  1480. DbgPrint ("************************************************\n");
  1481. DbgPrint ("*AFD: IoCallDriver returned STATUS_SUCCESS,"
  1482. " but event in the IRP (%p) is NOT signalled!!!\n",
  1483. irp);
  1484. DbgPrint ("************************************************\n");
  1485. DbgBreakPoint ();
  1486. }
  1487. }
  1488. //
  1489. // If the request was successfully completed, get the final I/O status.
  1490. //
  1491. if ( NT_SUCCESS(status) ) {
  1492. status = ioStatusBlock.Status;
  1493. }
  1494. //
  1495. // Since this option is only supported for TCP/IP, always return success.
  1496. //
  1497. return STATUS_SUCCESS;
  1498. } // AfdSetInLineMode
  1499. //
  1500. // The locking mechanism idea below is stolen from ntos\ex\handle.c
  1501. //
  1502. PVOID
  1503. AfdLockEndpointContext (
  1504. PAFD_ENDPOINT Endpoint
  1505. )
  1506. {
  1507. PVOID context;
  1508. PAGED_CODE ();
  1509. //
  1510. // We now use this lock in APC, protect from being
  1511. // interrupted by the APC by disallowing them when we
  1512. // are holding the lock.
  1513. //
  1514. KeEnterCriticalRegion ();
  1515. while (1) {
  1516. context = Endpoint->Context;
  1517. //
  1518. // See if someone else is manipulating the context.
  1519. //
  1520. if ((context==AFD_CONTEXT_BUSY) ||
  1521. (context==AFD_CONTEXT_WAITING)) {
  1522. //
  1523. // If this has not changed while we were checking,
  1524. // tell the current owner that we are waiting (if not
  1525. // already told) and wait for a few miliseconds.
  1526. //
  1527. if (InterlockedCompareExchangePointer (
  1528. (PVOID *)&Endpoint->Context,
  1529. AFD_CONTEXT_WAITING,
  1530. context)==context) {
  1531. NTSTATUS status;
  1532. LARGE_INTEGER afd10Milliseconds = {(ULONG)(-10 * 1000 * 10), -1};
  1533. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1534. "AfdLockEndpointContext: Waiting for endp %p\n",
  1535. Endpoint));
  1536. KeLeaveCriticalRegion ();
  1537. status = KeWaitForSingleObject( (PVOID)&AfdContextWaitEvent,
  1538. Executive,
  1539. KernelMode,
  1540. FALSE,
  1541. &afd10Milliseconds);
  1542. KeEnterCriticalRegion ();
  1543. }
  1544. else {
  1545. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1546. "AfdLockEndpointContext: ICEP contention on %p\n",
  1547. Endpoint));
  1548. }
  1549. //
  1550. // Try again.
  1551. //
  1552. }
  1553. else {
  1554. //
  1555. // Context is not owned, try to get the ownership
  1556. //
  1557. if (InterlockedCompareExchangePointer (
  1558. (PVOID *)&Endpoint->Context,
  1559. AFD_CONTEXT_BUSY,
  1560. context)==context) {
  1561. //
  1562. // We now own the context, return it.
  1563. //
  1564. break;
  1565. }
  1566. //
  1567. // Try again.
  1568. //
  1569. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1570. "AfdLockEndpointContext: ICEP contention on %p\n",
  1571. Endpoint));
  1572. }
  1573. }
  1574. return context;
  1575. }
  1576. VOID
  1577. AfdUnlockEndpointContext (
  1578. PAFD_ENDPOINT Endpoint,
  1579. PVOID Context
  1580. )
  1581. {
  1582. PAGED_CODE ();
  1583. ASSERT ((Context!=AFD_CONTEXT_BUSY) && (Context!=AFD_CONTEXT_WAITING));
  1584. //
  1585. // Set the new context pointer and see what the old value was.
  1586. //
  1587. Context = InterlockedExchangePointer ((PVOID)&Endpoint->Context, Context);
  1588. if (Context==AFD_CONTEXT_WAITING) {
  1589. LONG prevState;
  1590. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  1591. "AfdUnlockEndpointContext: Unwaiting endp %p\n", Endpoint));
  1592. //
  1593. // Someone was waiting, tell them to go get it now.
  1594. //
  1595. prevState = KePulseEvent (&AfdContextWaitEvent,
  1596. AfdPriorityBoost,
  1597. FALSE
  1598. );
  1599. ASSERT (prevState==0);
  1600. }
  1601. else {
  1602. //
  1603. // Better be busy or someone has changed it on us.
  1604. //
  1605. ASSERT (Context==AFD_CONTEXT_BUSY);
  1606. }
  1607. KeLeaveCriticalRegion ();
  1608. }
  1609. NTSTATUS
  1610. AfdGetContext (
  1611. IN PFILE_OBJECT FileObject,
  1612. IN ULONG IoctlCode,
  1613. IN KPROCESSOR_MODE RequestorMode,
  1614. IN PVOID InputBuffer,
  1615. IN ULONG InputBufferLength,
  1616. IN PVOID OutputBuffer,
  1617. IN ULONG OutputBufferLength,
  1618. OUT PUINT_PTR Information
  1619. )
  1620. {
  1621. PAFD_ENDPOINT endpoint;
  1622. PVOID context;
  1623. NTSTATUS status;
  1624. PAGED_CODE( );
  1625. //
  1626. // Set up local pointers.
  1627. //
  1628. endpoint = FileObject->FsContext;
  1629. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1630. *Information = 0;
  1631. context = AfdLockEndpointContext (endpoint);
  1632. //
  1633. // Make sure that the output buffer is large enough to hold all the
  1634. // context information for this socket.
  1635. //
  1636. //
  1637. // If there is no context, return nothing.
  1638. //
  1639. if ( context == NULL ) {
  1640. status = STATUS_INVALID_PARAMETER;
  1641. }
  1642. //
  1643. // Return the context information we have stored for this endpoint.
  1644. //
  1645. else {
  1646. //
  1647. // If application buffer is too small, just
  1648. // copy whatever fits in and return the error code.
  1649. //
  1650. if ( OutputBufferLength < endpoint->ContextLength ) {
  1651. status = STATUS_BUFFER_OVERFLOW;
  1652. }
  1653. else {
  1654. OutputBufferLength = endpoint->ContextLength;
  1655. if (IS_SAN_ENDPOINT (endpoint)) {
  1656. //
  1657. // Indicate to the caller that it may also need to
  1658. // acqiure the control of the endpoint and
  1659. // fetch san specific information.
  1660. //
  1661. status = STATUS_MORE_ENTRIES;
  1662. }
  1663. else {
  1664. status = STATUS_SUCCESS;
  1665. }
  1666. }
  1667. try {
  1668. //
  1669. // Validate the output structure if it comes from the user mode
  1670. // application
  1671. //
  1672. if (RequestorMode != KernelMode ) {
  1673. ProbeForWrite (OutputBuffer,
  1674. OutputBufferLength,
  1675. sizeof (UCHAR));
  1676. }
  1677. //
  1678. // Copy parameters back to application's memory
  1679. //
  1680. RtlCopyMemory(
  1681. OutputBuffer,
  1682. context,
  1683. OutputBufferLength
  1684. );
  1685. *Information = endpoint->ContextLength;
  1686. } except( AFD_EXCEPTION_FILTER(&status) ) {
  1687. }
  1688. }
  1689. AfdUnlockEndpointContext (endpoint, context);
  1690. return status;
  1691. } // AfdGetContext
  1692. NTSTATUS
  1693. AfdGetRemoteAddress (
  1694. IN PFILE_OBJECT FileObject,
  1695. IN ULONG IoctlCode,
  1696. IN KPROCESSOR_MODE RequestorMode,
  1697. IN PVOID InputBuffer,
  1698. IN ULONG InputBufferLength,
  1699. IN PVOID OutputBuffer,
  1700. IN ULONG OutputBufferLength,
  1701. OUT PUINT_PTR Information
  1702. )
  1703. {
  1704. PAFD_ENDPOINT endpoint;
  1705. PVOID context;
  1706. NTSTATUS status;
  1707. PAGED_CODE( );
  1708. //
  1709. // Set up local pointers.
  1710. //
  1711. endpoint = FileObject->FsContext;
  1712. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1713. *Information = 0;
  1714. context = AfdLockEndpointContext (endpoint);
  1715. //
  1716. // If there is no context or endpoint is of wrong type state or
  1717. // context information has been changed below the original size,
  1718. // return error.
  1719. //
  1720. if ( context == NULL ||
  1721. endpoint->Type!=AfdBlockTypeVcConnecting ||
  1722. endpoint->State!= AfdEndpointStateConnected ||
  1723. ((CLONG)(endpoint->Common.VcConnecting.RemoteSocketAddressOffset+
  1724. endpoint->Common.VcConnecting.RemoteSocketAddressLength)) >
  1725. endpoint->ContextLength
  1726. ) {
  1727. status = STATUS_INVALID_CONNECTION;
  1728. }
  1729. else {
  1730. if (OutputBufferLength<endpoint->Common.VcConnecting.RemoteSocketAddressLength) {
  1731. status = STATUS_BUFFER_OVERFLOW;
  1732. }
  1733. else {
  1734. OutputBufferLength = endpoint->Common.VcConnecting.RemoteSocketAddressLength;
  1735. status = STATUS_SUCCESS;
  1736. }
  1737. try {
  1738. //
  1739. // Validate the output structure if it comes from the user mode
  1740. // application
  1741. //
  1742. if (RequestorMode != KernelMode ) {
  1743. ProbeForWrite (OutputBuffer,
  1744. OutputBufferLength,
  1745. sizeof (UCHAR));
  1746. }
  1747. //
  1748. // Copy parameters to application's memory
  1749. //
  1750. RtlCopyMemory(
  1751. OutputBuffer,
  1752. (PUCHAR)context+endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
  1753. endpoint->Common.VcConnecting.RemoteSocketAddressLength
  1754. );
  1755. *Information = endpoint->ContextLength;
  1756. } except( AFD_EXCEPTION_FILTER(&status) ) {
  1757. }
  1758. }
  1759. AfdUnlockEndpointContext (endpoint, context);
  1760. return status;
  1761. } // AfdGetRemoteAddress
  1762. NTSTATUS
  1763. AfdSetContext (
  1764. IN PFILE_OBJECT FileObject,
  1765. IN ULONG IoctlCode,
  1766. IN KPROCESSOR_MODE RequestorMode,
  1767. IN PVOID InputBuffer,
  1768. IN ULONG InputBufferLength,
  1769. IN PVOID OutputBuffer,
  1770. IN ULONG OutputBufferLength,
  1771. OUT PUINT_PTR Information
  1772. )
  1773. {
  1774. PAFD_ENDPOINT endpoint;
  1775. PVOID context;
  1776. NTSTATUS status;
  1777. PAGED_CODE( );
  1778. //
  1779. // Set up local pointers.
  1780. //
  1781. endpoint = FileObject->FsContext;
  1782. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1783. status = STATUS_SUCCESS;
  1784. *Information = 0;
  1785. context = AfdLockEndpointContext (endpoint);
  1786. try {
  1787. //
  1788. // Validate the input structure if it comes from the user mode
  1789. // application
  1790. //
  1791. if (RequestorMode != KernelMode ) {
  1792. ProbeForRead (InputBuffer,
  1793. InputBufferLength,
  1794. sizeof (UCHAR));
  1795. if (OutputBuffer!=NULL) {
  1796. //
  1797. // Validate that output buffer is completely inside
  1798. // of the input buffer and offsets are inside of supported ranges.
  1799. //
  1800. if ((PUCHAR)OutputBuffer<(PUCHAR)InputBuffer ||
  1801. (PUCHAR)OutputBuffer-(PUCHAR)InputBuffer>MAXUSHORT ||
  1802. OutputBufferLength>MAXUSHORT ||
  1803. OutputBufferLength>InputBufferLength ||
  1804. (ULONG)((PUCHAR)OutputBuffer-(PUCHAR)InputBuffer)>
  1805. InputBufferLength-OutputBufferLength) {
  1806. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  1807. }
  1808. }
  1809. }
  1810. //
  1811. // If the context buffer is too small, allocate a new context
  1812. // buffer from paged pool.
  1813. //
  1814. if ( endpoint->ContextLength < InputBufferLength ) {
  1815. PVOID newContext;
  1816. //
  1817. // Allocate a new context buffer.
  1818. // Note since the socket context usually gets
  1819. // populated on socket creation during boot and not used
  1820. // right away (untill socket state is chaged), we
  1821. // make it a "cold" allocation. The flag has no effect
  1822. // after system is booted.
  1823. newContext = AFD_ALLOCATE_POOL_WITH_QUOTA(
  1824. PagedPool|POOL_COLD_ALLOCATION,
  1825. InputBufferLength,
  1826. AFD_CONTEXT_POOL_TAG
  1827. );
  1828. // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
  1829. ASSERT ( newContext != NULL );
  1830. //
  1831. // Free the old context buffer, if there was one.
  1832. //
  1833. if ( context != NULL ) {
  1834. AFD_FREE_POOL(
  1835. context,
  1836. AFD_CONTEXT_POOL_TAG
  1837. );
  1838. }
  1839. context = newContext;
  1840. }
  1841. //
  1842. // Store the passed-in context buffer.
  1843. //
  1844. endpoint->ContextLength = InputBufferLength;
  1845. RtlCopyMemory(
  1846. context,
  1847. InputBuffer,
  1848. InputBufferLength
  1849. );
  1850. status = STATUS_SUCCESS;
  1851. //
  1852. // Save pointer to remote socket address which we fill
  1853. // at the time of AcceptEx processing.
  1854. //
  1855. if (OutputBuffer!=NULL) {
  1856. if (AFD_START_STATE_CHANGE (endpoint, AfdEndpointStateOpen)) {
  1857. if (endpoint->Type==AfdBlockTypeEndpoint &&
  1858. endpoint->State==AfdEndpointStateOpen) {
  1859. endpoint->Common.VcConnecting.RemoteSocketAddressOffset =
  1860. (USHORT) ((PUCHAR)OutputBuffer-(PUCHAR)InputBuffer);
  1861. endpoint->Common.VcConnecting.RemoteSocketAddressLength =
  1862. (USHORT) OutputBufferLength;
  1863. }
  1864. AFD_END_STATE_CHANGE (endpoint);
  1865. }
  1866. }
  1867. }
  1868. except (AFD_EXCEPTION_FILTER (&status)) {
  1869. }
  1870. AfdUnlockEndpointContext (endpoint, context);
  1871. return status;
  1872. } // AfdSetContext
  1873. NTSTATUS
  1874. AfdSetEventHandler (
  1875. IN PFILE_OBJECT FileObject,
  1876. IN ULONG EventType,
  1877. IN PVOID EventHandler,
  1878. IN PVOID EventContext
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Sets up a TDI indication handler on a connection or address object
  1883. (depending on the file handle). This is done synchronously, which
  1884. shouldn't usually be an issue since TDI providers can usually complete
  1885. indication handler setups immediately.
  1886. Arguments:
  1887. FileObject - a pointer to the file object for an open connection or
  1888. address object.
  1889. EventType - the event for which the indication handler should be
  1890. called.
  1891. EventHandler - the routine to call when tghe specified event occurs.
  1892. EventContext - context which is passed to the indication routine.
  1893. Return Value:
  1894. NTSTATUS -- Indicates the status of the request.
  1895. --*/
  1896. {
  1897. TDI_REQUEST_KERNEL_SET_EVENT parameters;
  1898. PAGED_CODE( );
  1899. parameters.EventType = EventType;
  1900. parameters.EventHandler = EventHandler;
  1901. parameters.EventContext = EventContext;
  1902. return AfdIssueDeviceControl(
  1903. FileObject,
  1904. &parameters,
  1905. sizeof(parameters),
  1906. NULL,
  1907. 0,
  1908. TDI_SET_EVENT_HANDLER
  1909. );
  1910. } // AfdSetEventHandler
  1911. NTSTATUS
  1912. AfdIssueDeviceControl (
  1913. IN PFILE_OBJECT FileObject,
  1914. IN PVOID IrpParameters,
  1915. IN ULONG IrpParametersLength,
  1916. IN PVOID MdlBuffer,
  1917. IN ULONG MdlBufferLength,
  1918. IN UCHAR MinorFunction
  1919. )
  1920. /*++
  1921. Routine Description:
  1922. Issues a device control returst to a TDI provider and waits for the
  1923. request to complete.
  1924. Arguments:
  1925. FileObject - a pointer to the file object corresponding to a TDI
  1926. handle
  1927. IrpParameters - information to write to the parameters section of the
  1928. stack location of the IRP.
  1929. IrpParametersLength - length of the parameter information. Cannot be
  1930. greater than 16.
  1931. MdlBuffer - if non-NULL, a buffer of nonpaged pool to be mapped
  1932. into an MDL and placed in the MdlAddress field of the IRP.
  1933. MdlBufferLength - the size of the buffer pointed to by MdlBuffer.
  1934. MinorFunction - the minor function code for the request.
  1935. Return Value:
  1936. NTSTATUS -- Indicates the status of the request.
  1937. --*/
  1938. {
  1939. NTSTATUS status;
  1940. PIRP irp;
  1941. PIO_STACK_LOCATION irpSp;
  1942. KEVENT event;
  1943. IO_STATUS_BLOCK ioStatusBlock;
  1944. PDEVICE_OBJECT deviceObject;
  1945. PMDL mdl;
  1946. PAGED_CODE( );
  1947. //
  1948. // Initialize the kernel event that will signal I/O completion.
  1949. //
  1950. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  1951. //
  1952. // Attempt to allocate and initialize the I/O Request Packet (IRP)
  1953. // for this operation.
  1954. //
  1955. deviceObject = IoGetRelatedDeviceObject ( FileObject );
  1956. DEBUG ioStatusBlock.Status = STATUS_UNSUCCESSFUL;
  1957. DEBUG ioStatusBlock.Information = (ULONG)-1;
  1958. //
  1959. // If an MDL buffer was specified, get an MDL, and map the buffer
  1960. //
  1961. if ( MdlBuffer != NULL ) {
  1962. mdl = IoAllocateMdl(
  1963. MdlBuffer,
  1964. MdlBufferLength,
  1965. FALSE,
  1966. FALSE,
  1967. NULL
  1968. );
  1969. if ( mdl == NULL ) {
  1970. return STATUS_INSUFFICIENT_RESOURCES;
  1971. }
  1972. MmBuildMdlForNonPagedPool( mdl );
  1973. } else {
  1974. mdl = NULL;
  1975. }
  1976. irp = TdiBuildInternalDeviceControlIrp (
  1977. MinorFunction,
  1978. deviceObject,
  1979. FileObject,
  1980. &event,
  1981. &ioStatusBlock
  1982. );
  1983. if ( irp == NULL ) {
  1984. if (mdl!=NULL) {
  1985. IoFreeMdl (mdl);
  1986. }
  1987. return STATUS_INSUFFICIENT_RESOURCES;
  1988. }
  1989. //
  1990. // Install MDL (if any) in the IRP.
  1991. //
  1992. irp->MdlAddress = mdl;
  1993. //
  1994. // Put the file object pointer in the stack location.
  1995. //
  1996. irpSp = IoGetNextIrpStackLocation( irp );
  1997. ASSERT (irpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
  1998. irpSp->MinorFunction = MinorFunction;
  1999. irpSp->FileObject = FileObject;
  2000. //
  2001. // Fill in the service-dependent parameters for the request.
  2002. //
  2003. ASSERT( IrpParametersLength <= sizeof(irpSp->Parameters) );
  2004. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  2005. //
  2006. // Set up a completion routine which we'll use to free the MDL
  2007. // allocated previously.
  2008. //
  2009. IoSetCompletionRoutine( irp, AfdRestartDeviceControl, NULL, TRUE, TRUE, TRUE );
  2010. status = IoCallDriver( deviceObject, irp );
  2011. //
  2012. // Must be at below APC level or this IRP will never get fully completed.
  2013. //
  2014. ASSERT (KeGetCurrentIrql ()<APC_LEVEL);
  2015. //
  2016. // If necessary, wait for the I/O to complete.
  2017. //
  2018. if ( status == STATUS_PENDING ) {
  2019. status = KeWaitForSingleObject( (PVOID)&event, Executive, KernelMode, FALSE, NULL );
  2020. ASSERT (status==STATUS_SUCCESS);
  2021. }
  2022. else {
  2023. //
  2024. // The IRP must have been completed then and event set.
  2025. //
  2026. if (NT_ERROR (status) || KeReadStateEvent (&event))
  2027. ;
  2028. else {
  2029. DbgPrint ("************************************************\n");
  2030. DbgPrint ("*AFD: IoCallDriver returned STATUS_SUCCESS,"
  2031. " but event in the IRP (%p) is NOT signalled!!!\n",
  2032. irp);
  2033. DbgPrint ("************************************************\n");
  2034. DbgBreakPoint ();
  2035. }
  2036. }
  2037. //
  2038. // If the request was successfully completed, get the final I/O status.
  2039. //
  2040. if ( NT_SUCCESS(status) ) {
  2041. status = ioStatusBlock.Status;
  2042. }
  2043. return status;
  2044. } // AfdIssueDeviceControl
  2045. NTSTATUS
  2046. AfdRestartDeviceControl (
  2047. IN PDEVICE_OBJECT DeviceObject,
  2048. IN PIRP Irp,
  2049. IN PVOID Context
  2050. )
  2051. {
  2052. //
  2053. // N.B. This routine can never be demand paged because it can be
  2054. // called before any endpoints have been placed on the global
  2055. // list--see AfdAllocateEndpoint() and it's call to
  2056. // AfdGetTransportInfo().
  2057. //
  2058. //
  2059. // If there was an MDL in the IRP, free it and reset the pointer to
  2060. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  2061. // in an IRP, which is why we do it here.
  2062. //
  2063. if ( Irp->MdlAddress != NULL ) {
  2064. IoFreeMdl( Irp->MdlAddress );
  2065. Irp->MdlAddress = NULL;
  2066. }
  2067. return STATUS_SUCCESS;
  2068. } // AfdRestartDeviceControl
  2069. NTSTATUS
  2070. AfdGetConnectData (
  2071. IN PFILE_OBJECT FileObject,
  2072. IN ULONG IoctlCode,
  2073. IN KPROCESSOR_MODE RequestorMode,
  2074. IN PVOID InputBuffer,
  2075. IN ULONG InputBufferLength,
  2076. IN PVOID OutputBuffer,
  2077. IN ULONG OutputBufferLength,
  2078. OUT PUINT_PTR Information
  2079. )
  2080. {
  2081. PAFD_ENDPOINT endpoint;
  2082. PAFD_CONNECTION connection;
  2083. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  2084. PAFD_CONNECT_DATA_INFO connectDataInfo;
  2085. AFD_UNACCEPTED_CONNECT_DATA_INFO connectInfo;
  2086. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2087. PMDL mdl;
  2088. NTSTATUS status;
  2089. UCHAR localBuffer[AFD_FAST_CONNECT_DATA_SIZE];
  2090. //
  2091. // Set up local pointers.
  2092. //
  2093. endpoint = FileObject->FsContext;
  2094. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2095. mdl = NULL;
  2096. status = STATUS_SUCCESS;
  2097. *Information = 0;
  2098. try {
  2099. if (InputBufferLength>0) {
  2100. if (InputBufferLength<sizeof(connectInfo)) {
  2101. status = STATUS_INVALID_PARAMETER;
  2102. goto exit;
  2103. }
  2104. //
  2105. // Validate the input structure if it comes from the user mode
  2106. // application
  2107. //
  2108. if (RequestorMode != KernelMode ) {
  2109. ProbeForRead (InputBuffer,
  2110. sizeof (connectInfo),
  2111. PROBE_ALIGNMENT(AFD_UNACCEPTED_CONNECT_DATA_INFO));
  2112. }
  2113. //
  2114. // Make local copies of the embeded pointer and parameters
  2115. // that we will be using more than once in case malicios
  2116. // application attempts to change them while we are
  2117. // validating
  2118. //
  2119. connectInfo = *((PAFD_UNACCEPTED_CONNECT_DATA_INFO)InputBuffer);
  2120. if (connectInfo.LengthOnly &&
  2121. OutputBufferLength<sizeof (connectInfo)) {
  2122. status = STATUS_INVALID_PARAMETER;
  2123. goto exit;
  2124. }
  2125. }
  2126. if (OutputBufferLength>0) {
  2127. if (OutputBufferLength>sizeof (localBuffer)) {
  2128. mdl = IoAllocateMdl(
  2129. OutputBuffer, // VirtualAddress
  2130. OutputBufferLength, // Length
  2131. FALSE, // SecondaryBuffer
  2132. TRUE, // ChargeQuota
  2133. NULL // Irp
  2134. );
  2135. if (mdl==NULL) {
  2136. status = STATUS_INSUFFICIENT_RESOURCES;
  2137. goto exit;
  2138. }
  2139. MmProbeAndLockPages(
  2140. mdl, // MemoryDescriptorList
  2141. RequestorMode, // AccessMode
  2142. IoWriteAccess // Operation
  2143. );
  2144. OutputBuffer = MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
  2145. if (OutputBuffer==NULL) {
  2146. status = STATUS_INSUFFICIENT_RESOURCES;
  2147. goto exit;
  2148. }
  2149. }
  2150. else {
  2151. if (RequestorMode!=KernelMode) {
  2152. ProbeForWrite (OutputBuffer,
  2153. OutputBufferLength,
  2154. sizeof (UCHAR));
  2155. }
  2156. }
  2157. }
  2158. } except( AFD_EXCEPTION_FILTER(&status) ) {
  2159. goto exit;
  2160. }
  2161. //
  2162. // If there is a connection on this endpoint, use the data buffers
  2163. // on the connection. Otherwise, use the data buffers from the
  2164. // endpoint.
  2165. //
  2166. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  2167. if (InputBufferLength>0) {
  2168. if ((endpoint->Type & AfdBlockTypeVcListening)==AfdBlockTypeVcListening) {
  2169. connection = AfdFindReturnedConnection(
  2170. endpoint,
  2171. connectInfo.Sequence
  2172. );
  2173. }
  2174. else
  2175. connection = NULL;
  2176. if( connection == NULL ) {
  2177. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2178. status = STATUS_INVALID_PARAMETER;
  2179. goto exit;
  2180. }
  2181. connectDataBuffers = connection->ConnectDataBuffers;
  2182. }
  2183. else if ( (connection= AFD_CONNECTION_FROM_ENDPOINT (endpoint)) != NULL ) {
  2184. connectDataBuffers = connection->ConnectDataBuffers;
  2185. } else if (IS_VC_ENDPOINT (endpoint)) {
  2186. connectDataBuffers = endpoint->Common.VirtualCircuit.ConnectDataBuffers;
  2187. }
  2188. else {
  2189. connectDataBuffers = NULL;
  2190. }
  2191. //
  2192. // If there are no connect data buffers on the endpoint, complete
  2193. // the IRP with no bytes.
  2194. //
  2195. if ( connectDataBuffers == NULL ) {
  2196. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2197. status = STATUS_SUCCESS;
  2198. goto exit;
  2199. }
  2200. //
  2201. // Determine what sort of data we're handling and where it should
  2202. // come from.
  2203. //
  2204. switch ( IoctlCode ) {
  2205. case IOCTL_AFD_GET_CONNECT_DATA:
  2206. connectDataInfo = &connectDataBuffers->ReceiveConnectData;
  2207. break;
  2208. case IOCTL_AFD_GET_CONNECT_OPTIONS:
  2209. connectDataInfo = &connectDataBuffers->ReceiveConnectOptions;
  2210. break;
  2211. case IOCTL_AFD_GET_DISCONNECT_DATA:
  2212. connectDataInfo = &connectDataBuffers->ReceiveDisconnectData;
  2213. break;
  2214. case IOCTL_AFD_GET_DISCONNECT_OPTIONS:
  2215. connectDataInfo = &connectDataBuffers->ReceiveDisconnectOptions;
  2216. break;
  2217. default:
  2218. ASSERT(!"Unknown GET_CONNECT_DATA IOCTL!");
  2219. __assume (0);
  2220. }
  2221. if ((InputBufferLength>0) && connectInfo.LengthOnly) {
  2222. connectInfo.ConnectDataLength = connectDataInfo->BufferLength;
  2223. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2224. try {
  2225. RtlCopyMemory (OutputBuffer,
  2226. &connectInfo,
  2227. sizeof (connectInfo));
  2228. *Information = sizeof (connectInfo);
  2229. status = STATUS_SUCCESS;
  2230. }
  2231. except (AFD_EXCEPTION_FILTER (&status)) {
  2232. }
  2233. goto exit;
  2234. }
  2235. //
  2236. // If there is none of the requested data type, again complete
  2237. // the IRP with no bytes.
  2238. //
  2239. if ( connectDataInfo->Buffer == NULL ||
  2240. connectDataInfo->BufferLength == 0 ) {
  2241. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2242. *Information = 0;
  2243. status = STATUS_SUCCESS;
  2244. goto exit;
  2245. }
  2246. //
  2247. // If the output buffer is too small, fail.
  2248. //
  2249. if ( OutputBufferLength < connectDataInfo->BufferLength ) {
  2250. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2251. status = STATUS_BUFFER_TOO_SMALL;
  2252. goto exit;
  2253. }
  2254. //
  2255. // Copy over the buffer and return the number of bytes copied.
  2256. //
  2257. RtlCopyMemory(
  2258. mdl ? OutputBuffer : localBuffer,
  2259. connectDataInfo->Buffer,
  2260. connectDataInfo->BufferLength
  2261. );
  2262. *Information = connectDataInfo->BufferLength;
  2263. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2264. if (mdl==NULL) {
  2265. try {
  2266. RtlCopyMemory (OutputBuffer,
  2267. localBuffer,
  2268. *Information);
  2269. }
  2270. except (AFD_EXCEPTION_FILTER(&status)) {
  2271. *Information = 0;
  2272. }
  2273. }
  2274. exit:
  2275. if (mdl!=NULL) {
  2276. if (mdl->MdlFlags & MDL_PAGES_LOCKED) {
  2277. MmUnlockPages (mdl);
  2278. }
  2279. IoFreeMdl (mdl);
  2280. }
  2281. return status;
  2282. } // AfdGetConnectData
  2283. NTSTATUS
  2284. AfdSetConnectData (
  2285. IN PFILE_OBJECT FileObject,
  2286. IN ULONG IoctlCode,
  2287. IN KPROCESSOR_MODE RequestorMode,
  2288. IN PVOID InputBuffer,
  2289. IN ULONG InputBufferLength,
  2290. IN PVOID OutputBuffer,
  2291. IN ULONG OutputBufferLength,
  2292. OUT PUINT_PTR Information
  2293. )
  2294. {
  2295. PAFD_ENDPOINT endpoint;
  2296. PAFD_CONNECTION connection;
  2297. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  2298. PAFD_CONNECT_DATA_BUFFERS * connectDataBuffersTarget;
  2299. PAFD_CONNECT_DATA_INFO connectDataInfo;
  2300. AFD_UNACCEPTED_CONNECT_DATA_INFO connectInfo;
  2301. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2302. BOOLEAN size = FALSE;
  2303. PMDL mdl;
  2304. NTSTATUS status;
  2305. UCHAR localBuffer[AFD_FAST_CONNECT_DATA_SIZE];
  2306. //
  2307. // Set up local pointers.
  2308. //
  2309. endpoint = FileObject->FsContext;
  2310. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2311. mdl = NULL;
  2312. status = STATUS_SUCCESS;
  2313. *Information = 0;
  2314. if (!IS_VC_ENDPOINT (endpoint)) {
  2315. status = STATUS_INVALID_PARAMETER;
  2316. goto exit;
  2317. }
  2318. try {
  2319. if (InputBufferLength>0) {
  2320. if (InputBufferLength<sizeof(connectInfo)) {
  2321. status = STATUS_INVALID_PARAMETER;
  2322. goto exit;
  2323. }
  2324. //
  2325. // Validate the input structure if it comes from the user mode
  2326. // application
  2327. //
  2328. if (RequestorMode != KernelMode ) {
  2329. ProbeForRead (InputBuffer,
  2330. sizeof (connectInfo),
  2331. PROBE_ALIGNMENT(AFD_UNACCEPTED_CONNECT_DATA_INFO));
  2332. }
  2333. //
  2334. // Make local copies of the embeded pointer and parameters
  2335. // that we will be using more than once in case malicios
  2336. // application attempts to change them while we are
  2337. // validating
  2338. //
  2339. connectInfo = *((PAFD_UNACCEPTED_CONNECT_DATA_INFO)InputBuffer);
  2340. }
  2341. if (OutputBufferLength>0) {
  2342. if (OutputBufferLength>sizeof (localBuffer)) {
  2343. mdl = IoAllocateMdl(
  2344. OutputBuffer, // VirtualAddress
  2345. OutputBufferLength, // Length
  2346. FALSE, // SecondaryBuffer
  2347. TRUE, // ChargeQuota
  2348. NULL // Irp
  2349. );
  2350. if (mdl==NULL) {
  2351. status = STATUS_INSUFFICIENT_RESOURCES;
  2352. goto exit;
  2353. }
  2354. MmProbeAndLockPages(
  2355. mdl, // MemoryDescriptorList
  2356. RequestorMode, // AccessMode
  2357. IoReadAccess // Operation
  2358. );
  2359. OutputBuffer = MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
  2360. if (OutputBuffer==NULL) {
  2361. status = STATUS_INSUFFICIENT_RESOURCES;
  2362. goto exit;
  2363. }
  2364. }
  2365. else {
  2366. if (RequestorMode!=KernelMode) {
  2367. ProbeForRead (OutputBuffer,
  2368. OutputBufferLength,
  2369. sizeof (UCHAR));
  2370. RtlCopyMemory (localBuffer,
  2371. OutputBuffer,
  2372. OutputBufferLength);
  2373. OutputBuffer = localBuffer;
  2374. }
  2375. }
  2376. }
  2377. } except( AFD_EXCEPTION_FILTER(&status) ) {
  2378. goto exit;
  2379. }
  2380. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  2381. //
  2382. // If there is a connect outstanding on this endpoint or if it
  2383. // has already been shut down, fail this request. This prevents
  2384. // the connect code from accessing buffers which may be freed soon.
  2385. //
  2386. if( endpoint->StateChangeInProgress ||
  2387. ((endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 )) {
  2388. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2389. status = STATUS_INVALID_PARAMETER;
  2390. goto exit;
  2391. }
  2392. if (InputBufferLength>0) {
  2393. if ((endpoint->Type & AfdBlockTypeVcListening)==AfdBlockTypeVcListening) {
  2394. connection = AfdFindReturnedConnection(
  2395. endpoint,
  2396. connectInfo.Sequence
  2397. );
  2398. }
  2399. else
  2400. connection = NULL;
  2401. if( connection == NULL ) {
  2402. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2403. status = STATUS_INVALID_PARAMETER;
  2404. goto exit;
  2405. }
  2406. connectDataBuffersTarget = &connection->ConnectDataBuffers;
  2407. }
  2408. else if ( (connection= AFD_CONNECTION_FROM_ENDPOINT (endpoint)) != NULL ) {
  2409. connectDataBuffersTarget = &connection->ConnectDataBuffers;
  2410. } else {
  2411. connectDataBuffersTarget = &endpoint->Common.VirtualCircuit.ConnectDataBuffers;
  2412. }
  2413. connectDataBuffers = *connectDataBuffersTarget;
  2414. if( connectDataBuffers == NULL ) {
  2415. try {
  2416. connectDataBuffers = AFD_ALLOCATE_POOL_WITH_QUOTA(
  2417. NonPagedPool,
  2418. sizeof(*connectDataBuffers),
  2419. AFD_CONNECT_DATA_POOL_TAG
  2420. );
  2421. // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
  2422. ASSERT ( connectDataBuffers != NULL );
  2423. *connectDataBuffersTarget = connectDataBuffers;
  2424. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2425. status = GetExceptionCode ();
  2426. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2427. goto exit;
  2428. }
  2429. RtlZeroMemory(
  2430. connectDataBuffers,
  2431. sizeof(*connectDataBuffers)
  2432. );
  2433. }
  2434. //
  2435. // Determine what sort of data we're handling and where it should
  2436. // go.
  2437. //
  2438. switch( IoctlCode ) {
  2439. case IOCTL_AFD_SET_CONNECT_DATA:
  2440. connectDataInfo = &connectDataBuffers->SendConnectData;
  2441. break;
  2442. case IOCTL_AFD_SET_CONNECT_OPTIONS:
  2443. connectDataInfo = &connectDataBuffers->SendConnectOptions;
  2444. break;
  2445. case IOCTL_AFD_SET_DISCONNECT_DATA:
  2446. connectDataInfo = &connectDataBuffers->SendDisconnectData;
  2447. break;
  2448. case IOCTL_AFD_SET_DISCONNECT_OPTIONS:
  2449. connectDataInfo = &connectDataBuffers->SendDisconnectOptions;
  2450. break;
  2451. case IOCTL_AFD_SIZE_CONNECT_DATA:
  2452. connectDataInfo = &connectDataBuffers->ReceiveConnectData;
  2453. size = TRUE;
  2454. break;
  2455. case IOCTL_AFD_SIZE_CONNECT_OPTIONS:
  2456. connectDataInfo = &connectDataBuffers->ReceiveConnectOptions;
  2457. size = TRUE;
  2458. break;
  2459. case IOCTL_AFD_SIZE_DISCONNECT_DATA:
  2460. connectDataInfo = &connectDataBuffers->ReceiveDisconnectData;
  2461. size = TRUE;
  2462. break;
  2463. case IOCTL_AFD_SIZE_DISCONNECT_OPTIONS:
  2464. connectDataInfo = &connectDataBuffers->ReceiveDisconnectOptions;
  2465. size = TRUE;
  2466. break;
  2467. default:
  2468. ASSERT(FALSE);
  2469. }
  2470. //
  2471. // Determine the buffer size based on whether we're setting a buffer
  2472. // into which data will be received, in which case the size is
  2473. // in the four bytes of input buffer, or setting a buffer which we're
  2474. // going to send, in which case the size is the length of the input
  2475. // buffer.
  2476. //
  2477. if( size ) {
  2478. if( OutputBufferLength < sizeof(ULONG) ) {
  2479. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2480. status = STATUS_INVALID_PARAMETER;
  2481. goto exit;
  2482. }
  2483. OutputBufferLength = *(ULONG UNALIGNED *)OutputBuffer;
  2484. }
  2485. //
  2486. // If there's not currently a buffer of the requested type, or there is
  2487. // such a buffer and it's smaller than the requested size, free it
  2488. // and allocate a new one.
  2489. //
  2490. if( connectDataInfo->Buffer == NULL ||
  2491. connectDataInfo->BufferLength < OutputBufferLength ) {
  2492. if( connectDataInfo->Buffer != NULL ) {
  2493. AFD_FREE_POOL(
  2494. connectDataInfo->Buffer,
  2495. AFD_CONNECT_DATA_POOL_TAG
  2496. );
  2497. }
  2498. connectDataInfo->Buffer = NULL;
  2499. connectDataInfo->BufferLength = 0;
  2500. if (OutputBufferLength>0) {
  2501. try {
  2502. connectDataInfo->Buffer = AFD_ALLOCATE_POOL_WITH_QUOTA(
  2503. NonPagedPool,
  2504. OutputBufferLength,
  2505. AFD_CONNECT_DATA_POOL_TAG
  2506. );
  2507. // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
  2508. ASSERT ( connectDataInfo->Buffer != NULL );
  2509. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2510. status = GetExceptionCode ();
  2511. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2512. goto exit;
  2513. }
  2514. RtlZeroMemory(
  2515. connectDataInfo->Buffer,
  2516. OutputBufferLength
  2517. );
  2518. }
  2519. }
  2520. //
  2521. // If this wasn't simply a "size" request, copy the data into the buffer.
  2522. //
  2523. if( !size ) {
  2524. RtlCopyMemory(
  2525. connectDataInfo->Buffer,
  2526. OutputBuffer,
  2527. OutputBufferLength
  2528. );
  2529. }
  2530. connectDataInfo->BufferLength = OutputBufferLength;
  2531. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  2532. exit:
  2533. if (mdl!=NULL) {
  2534. if (mdl->MdlFlags & MDL_PAGES_LOCKED) {
  2535. MmUnlockPages (mdl);
  2536. }
  2537. IoFreeMdl (mdl);
  2538. }
  2539. return status;
  2540. } // AfdSetConnectData
  2541. NTSTATUS
  2542. AfdSaveReceivedConnectData (
  2543. IN OUT PAFD_CONNECT_DATA_BUFFERS * DataBuffers,
  2544. IN ULONG IoControlCode,
  2545. IN PVOID Buffer,
  2546. IN ULONG BufferLength
  2547. )
  2548. /*++
  2549. Routine Description:
  2550. This helper routine stores the specified *received* connect/disconnect
  2551. data/options on the specified endpoint/connection.
  2552. N.B. This routine MUST be called with endpoint SpinLock held!
  2553. N.B. Unlike AfdSetConnectData(), this routine cannot allocate the
  2554. AFD_CONNECT_DATA_BUFFERS structure with quota, as it may be
  2555. called from AfdDisconnectEventHandler() in an unknown thread
  2556. context.
  2557. Arguments:
  2558. DataBuffers -Points to a pointer to the connect data buffers structure.
  2559. If the value pointed to by DataBuffers is NULL, then a new structure
  2560. is allocated, otherwise the existing structure is used.
  2561. IoControlCode - Specifies the type of data to save.
  2562. Buffer - Points to the buffer containing the data.
  2563. BufferLength - The length of Buffer.
  2564. Return Value:
  2565. NTSTATUS - The completion status.
  2566. --*/
  2567. {
  2568. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  2569. PAFD_CONNECT_DATA_INFO connectDataInfo;
  2570. ASSERT( KeGetCurrentIrql() >= DISPATCH_LEVEL );
  2571. //
  2572. // If there's no connect data buffer structure, allocate one now.
  2573. //
  2574. connectDataBuffers = *DataBuffers;
  2575. if( connectDataBuffers == NULL ) {
  2576. connectDataBuffers = AFD_ALLOCATE_POOL(
  2577. NonPagedPool,
  2578. sizeof(*connectDataBuffers),
  2579. AFD_CONNECT_DATA_POOL_TAG
  2580. );
  2581. if( connectDataBuffers == NULL ) {
  2582. return STATUS_INSUFFICIENT_RESOURCES;
  2583. }
  2584. RtlZeroMemory(
  2585. connectDataBuffers,
  2586. sizeof(*connectDataBuffers)
  2587. );
  2588. *DataBuffers = connectDataBuffers;
  2589. }
  2590. //
  2591. // Determine what sort of data we're handling and where it should
  2592. // go.
  2593. //
  2594. switch( IoControlCode ) {
  2595. case IOCTL_AFD_SET_CONNECT_DATA:
  2596. connectDataInfo = &connectDataBuffers->ReceiveConnectData;
  2597. break;
  2598. case IOCTL_AFD_SET_CONNECT_OPTIONS:
  2599. connectDataInfo = &connectDataBuffers->ReceiveConnectOptions;
  2600. break;
  2601. case IOCTL_AFD_SET_DISCONNECT_DATA:
  2602. connectDataInfo = &connectDataBuffers->ReceiveDisconnectData;
  2603. break;
  2604. case IOCTL_AFD_SET_DISCONNECT_OPTIONS:
  2605. connectDataInfo = &connectDataBuffers->ReceiveDisconnectOptions;
  2606. break;
  2607. default:
  2608. ASSERT(FALSE);
  2609. }
  2610. //
  2611. // If the buffer in the connect structure matches the one
  2612. // passed in, must be the same buffer we passed in the request.
  2613. // Just adjust the length.
  2614. //
  2615. if (connectDataInfo->Buffer==Buffer) {
  2616. ASSERT (connectDataInfo->BufferLength>=BufferLength);
  2617. connectDataInfo->BufferLength = BufferLength;
  2618. return STATUS_SUCCESS;
  2619. }
  2620. //
  2621. // If there was previously a buffer of the requested type, free it.
  2622. //
  2623. if( connectDataInfo->Buffer != NULL ) {
  2624. AFD_FREE_POOL(
  2625. connectDataInfo->Buffer,
  2626. AFD_CONNECT_DATA_POOL_TAG
  2627. );
  2628. connectDataInfo->Buffer = NULL;
  2629. }
  2630. //
  2631. // Allocate a new buffer for the data and copy in the data we're to
  2632. // send.
  2633. //
  2634. connectDataInfo->Buffer = AFD_ALLOCATE_POOL(
  2635. NonPagedPool,
  2636. BufferLength,
  2637. AFD_CONNECT_DATA_POOL_TAG
  2638. );
  2639. if( connectDataInfo->Buffer == NULL ) {
  2640. return STATUS_INSUFFICIENT_RESOURCES;
  2641. }
  2642. RtlCopyMemory(
  2643. connectDataInfo->Buffer,
  2644. Buffer,
  2645. BufferLength
  2646. );
  2647. connectDataInfo->BufferLength = BufferLength;
  2648. return STATUS_SUCCESS;
  2649. } // AfdSaveReceivedConnectData
  2650. VOID
  2651. AfdFreeConnectDataBuffers (
  2652. IN PAFD_CONNECT_DATA_BUFFERS ConnectDataBuffers
  2653. )
  2654. {
  2655. if ( ConnectDataBuffers->SendConnectData.Buffer != NULL ) {
  2656. AFD_FREE_POOL(
  2657. ConnectDataBuffers->SendConnectData.Buffer,
  2658. AFD_CONNECT_DATA_POOL_TAG
  2659. );
  2660. }
  2661. if ( ConnectDataBuffers->ReceiveConnectData.Buffer != NULL ) {
  2662. AFD_FREE_POOL(
  2663. ConnectDataBuffers->ReceiveConnectData.Buffer,
  2664. AFD_CONNECT_DATA_POOL_TAG
  2665. );
  2666. }
  2667. if ( ConnectDataBuffers->SendConnectOptions.Buffer != NULL ) {
  2668. AFD_FREE_POOL(
  2669. ConnectDataBuffers->SendConnectOptions.Buffer,
  2670. AFD_CONNECT_DATA_POOL_TAG
  2671. );
  2672. }
  2673. if ( ConnectDataBuffers->ReceiveConnectOptions.Buffer != NULL ) {
  2674. AFD_FREE_POOL(
  2675. ConnectDataBuffers->ReceiveConnectOptions.Buffer,
  2676. AFD_CONNECT_DATA_POOL_TAG
  2677. );
  2678. }
  2679. if ( ConnectDataBuffers->SendDisconnectData.Buffer != NULL ) {
  2680. AFD_FREE_POOL(
  2681. ConnectDataBuffers->SendDisconnectData.Buffer,
  2682. AFD_CONNECT_DATA_POOL_TAG
  2683. );
  2684. }
  2685. if ( ConnectDataBuffers->ReceiveDisconnectData.Buffer != NULL ) {
  2686. AFD_FREE_POOL(
  2687. ConnectDataBuffers->ReceiveDisconnectData.Buffer,
  2688. AFD_CONNECT_DATA_POOL_TAG
  2689. );
  2690. }
  2691. if ( ConnectDataBuffers->SendDisconnectOptions.Buffer != NULL ) {
  2692. AFD_FREE_POOL(
  2693. ConnectDataBuffers->SendDisconnectOptions.Buffer,
  2694. AFD_CONNECT_DATA_POOL_TAG
  2695. );
  2696. }
  2697. if ( ConnectDataBuffers->ReceiveDisconnectOptions.Buffer != NULL ) {
  2698. AFD_FREE_POOL(
  2699. ConnectDataBuffers->ReceiveDisconnectOptions.Buffer,
  2700. AFD_CONNECT_DATA_POOL_TAG
  2701. );
  2702. }
  2703. AFD_FREE_POOL(
  2704. ConnectDataBuffers,
  2705. AFD_CONNECT_DATA_POOL_TAG
  2706. );
  2707. return;
  2708. } // AfdFreeConnectDataBuffers
  2709. VOID
  2710. AfdQueueWorkItem (
  2711. IN PWORKER_THREAD_ROUTINE AfdWorkerRoutine,
  2712. IN PAFD_WORK_ITEM AfdWorkItem
  2713. )
  2714. {
  2715. KIRQL oldIrql;
  2716. ASSERT( AfdWorkerRoutine != NULL );
  2717. ASSERT( AfdWorkItem != NULL );
  2718. AfdWorkItem->AfdWorkerRoutine = AfdWorkerRoutine;
  2719. //
  2720. // Insert the work item at the tail of AFD's list of work itrems.
  2721. //
  2722. oldIrql = KeAcquireQueuedSpinLock( LockQueueAfdWorkQueueLock );
  2723. InsertTailList( &AfdWorkQueueListHead, &AfdWorkItem->WorkItemListEntry );
  2724. AfdRecordAfdWorkItemsQueued();
  2725. //
  2726. // If there is no executive worker thread working on AFD work, fire
  2727. // off an executive worker thread to start servicing the list.
  2728. //
  2729. if ( !AfdWorkThreadRunning ) {
  2730. //
  2731. // Remember that the work thread is running and release the
  2732. // lock. Note that we must release the lock before queuing the
  2733. // work because the worker thread may unlock AFD and we can't
  2734. // hold a lock when AFD is unlocked.
  2735. //
  2736. AfdRecordExWorkItemsQueued();
  2737. AfdWorkThreadRunning = TRUE;
  2738. KeReleaseQueuedSpinLock( LockQueueAfdWorkQueueLock, oldIrql );
  2739. IoQueueWorkItem (AfdWorkQueueItem,
  2740. AfdDoWork,
  2741. DelayedWorkQueue,
  2742. NULL);
  2743. } else {
  2744. KeReleaseQueuedSpinLock( LockQueueAfdWorkQueueLock, oldIrql );
  2745. }
  2746. return;
  2747. } // AfdQueueWorkItem
  2748. VOID
  2749. AfdDoWork (
  2750. IN PDEVICE_OBJECT DeviceObject,
  2751. IN PVOID Context
  2752. )
  2753. {
  2754. PAFD_WORK_ITEM afdWorkItem;
  2755. PLIST_ENTRY listEntry;
  2756. KIRQL oldIrql;
  2757. PWORKER_THREAD_ROUTINE workerRoutine;
  2758. ASSERT( AfdWorkThreadRunning );
  2759. //
  2760. // Empty the queue of AFD work items.
  2761. //
  2762. oldIrql = KeAcquireQueuedSpinLock( LockQueueAfdWorkQueueLock );
  2763. AfdRecordWorkerEnter();
  2764. AfdRecordAfdWorkerThread( PsGetCurrentThread() );
  2765. while ( !IsListEmpty( &AfdWorkQueueListHead ) ) {
  2766. //
  2767. // Take the first item from the queue and find the address
  2768. // of the AFD work item structure.
  2769. //
  2770. listEntry = RemoveHeadList( &AfdWorkQueueListHead );
  2771. afdWorkItem = CONTAINING_RECORD(
  2772. listEntry,
  2773. AFD_WORK_ITEM,
  2774. WorkItemListEntry
  2775. );
  2776. AfdRecordAfdWorkItemsProcessed();
  2777. //
  2778. // Capture the worker thread routine from the item.
  2779. //
  2780. workerRoutine = afdWorkItem->AfdWorkerRoutine;
  2781. //
  2782. // If this work item is going to unlock AFD, then remember that
  2783. // the worker thread is no longer running. This closes the
  2784. // window where AFD gets unloaded at the same time as new work
  2785. // comes in and gets put on the work queue. Note that we
  2786. // must reset this boolean BEFORE releasing the spin lock.
  2787. //
  2788. if( workerRoutine == AfdUnlockDriver ) {
  2789. AfdWorkThreadRunning = FALSE;
  2790. AfdRecordAfdWorkerThread( NULL );
  2791. AfdRecordWorkerLeave();
  2792. }
  2793. //
  2794. // Release the lock and then call the AFD worker routine.
  2795. //
  2796. KeReleaseQueuedSpinLock( LockQueueAfdWorkQueueLock, oldIrql );
  2797. workerRoutine( afdWorkItem );
  2798. //
  2799. // If the purpose of this work item was to unload AFD, then
  2800. // we know that there is no more work to do and we CANNOT
  2801. // acquire a spin lock. Quit servicing the list and return.
  2802. if( workerRoutine == AfdUnlockDriver ) {
  2803. return;
  2804. }
  2805. //
  2806. // Reacquire the spin lock and continue servicing the list.
  2807. //
  2808. oldIrql = KeAcquireQueuedSpinLock( LockQueueAfdWorkQueueLock );
  2809. }
  2810. //
  2811. // Remember that we're no longer servicing the list and release the
  2812. // spin lock.
  2813. //
  2814. AfdRecordAfdWorkerThread( NULL );
  2815. AfdRecordWorkerLeave();
  2816. AfdWorkThreadRunning = FALSE;
  2817. KeReleaseQueuedSpinLock( LockQueueAfdWorkQueueLock, oldIrql );
  2818. } // AfdDoWork
  2819. PAFD_WORK_ITEM
  2820. AfdGetWorkerByRoutine (
  2821. PWORKER_THREAD_ROUTINE Routine
  2822. ) {
  2823. KIRQL oldIrql;
  2824. PLIST_ENTRY listEntry;
  2825. oldIrql = KeAcquireQueuedSpinLock( LockQueueAfdWorkQueueLock );
  2826. listEntry = AfdWorkQueueListHead.Flink;
  2827. while (listEntry!=&AfdWorkQueueListHead) {
  2828. PAFD_WORK_ITEM afdWorkItem = CONTAINING_RECORD(
  2829. listEntry,
  2830. AFD_WORK_ITEM,
  2831. WorkItemListEntry
  2832. );
  2833. if (afdWorkItem->AfdWorkerRoutine==Routine) {
  2834. RemoveEntryList (&afdWorkItem->WorkItemListEntry);
  2835. KeReleaseQueuedSpinLock( LockQueueAfdWorkQueueLock, oldIrql );
  2836. return afdWorkItem;
  2837. }
  2838. else
  2839. listEntry = listEntry->Flink;
  2840. }
  2841. KeReleaseQueuedSpinLock( LockQueueAfdWorkQueueLock, oldIrql );
  2842. return NULL;
  2843. } // AfdGetWorkerByRoutine
  2844. #if DBG
  2845. typedef struct _AFD_OUTSTANDING_IRP {
  2846. LIST_ENTRY OutstandingIrpListEntry;
  2847. PIRP OutstandingIrp;
  2848. PCHAR FileName;
  2849. ULONG LineNumber;
  2850. } AFD_OUTSTANDING_IRP, *PAFD_OUTSTANDING_IRP;
  2851. BOOLEAN
  2852. AfdRecordOutstandingIrpDebug (
  2853. IN PAFD_ENDPOINT Endpoint,
  2854. IN PDEVICE_OBJECT DeviceObject,
  2855. IN PIRP Irp,
  2856. IN PCHAR FileName,
  2857. IN ULONG LineNumber
  2858. )
  2859. {
  2860. PAFD_OUTSTANDING_IRP outstandingIrp;
  2861. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2862. //
  2863. // Get an outstanding IRP structure to hold the IRP.
  2864. //
  2865. outstandingIrp = AFD_ALLOCATE_POOL_PRIORITY (
  2866. NonPagedPool,
  2867. sizeof(AFD_OUTSTANDING_IRP),
  2868. AFD_DEBUG_POOL_TAG,
  2869. NormalPoolPriority
  2870. );
  2871. if ( outstandingIrp == NULL ) {
  2872. //
  2873. // Because our completion routine will try to
  2874. // find this IRP anyway and check for completion
  2875. // we use the stack space to put it in the list.
  2876. // The completion routine will just remove this
  2877. // element from the list without attempting to free it.
  2878. //
  2879. AFD_OUTSTANDING_IRP OutstandingIrp;
  2880. OutstandingIrp.OutstandingIrp = Irp;
  2881. OutstandingIrp.FileName = NULL; // To let completion
  2882. // routine know that this
  2883. // is not an allocated element
  2884. OutstandingIrp.LineNumber = 0;
  2885. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  2886. InsertTailList(
  2887. &Endpoint->OutstandingIrpListHead,
  2888. &OutstandingIrp.OutstandingIrpListEntry
  2889. );
  2890. Endpoint->OutstandingIrpCount++;
  2891. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  2892. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  2893. "AfdRecordOutstandingIrp: Could not track Irp %p on endpoint %p, failing it.\n",
  2894. Irp, Endpoint));
  2895. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2896. IoSetNextIrpStackLocation( Irp );
  2897. IoCompleteRequest( Irp, AfdPriorityBoost );
  2898. return FALSE;
  2899. }
  2900. //
  2901. // Initialize the structure and place it on the endpoint's list of
  2902. // outstanding IRPs.
  2903. //
  2904. outstandingIrp->OutstandingIrp = Irp;
  2905. outstandingIrp->FileName = FileName;
  2906. outstandingIrp->LineNumber = LineNumber;
  2907. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  2908. InsertHeadList(
  2909. &Endpoint->OutstandingIrpListHead,
  2910. &outstandingIrp->OutstandingIrpListEntry
  2911. );
  2912. Endpoint->OutstandingIrpCount++;
  2913. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  2914. return TRUE;
  2915. } // AfdRecordOutstandingIrpDebug
  2916. VOID
  2917. AfdCompleteOutstandingIrpDebug (
  2918. IN PAFD_ENDPOINT Endpoint,
  2919. IN PIRP Irp
  2920. )
  2921. {
  2922. PAFD_OUTSTANDING_IRP outstandingIrp;
  2923. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2924. PLIST_ENTRY listEntry;
  2925. //
  2926. // First find the IRP on the endpoint's list of outstanding IRPs.
  2927. //
  2928. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  2929. for ( listEntry = Endpoint->OutstandingIrpListHead.Flink;
  2930. listEntry != &Endpoint->OutstandingIrpListHead;
  2931. listEntry = listEntry->Flink ) {
  2932. outstandingIrp = CONTAINING_RECORD(
  2933. listEntry,
  2934. AFD_OUTSTANDING_IRP,
  2935. OutstandingIrpListEntry
  2936. );
  2937. if ( outstandingIrp->OutstandingIrp == Irp ) {
  2938. RemoveEntryList( listEntry );
  2939. ASSERT( Endpoint->OutstandingIrpCount != 0 );
  2940. Endpoint->OutstandingIrpCount--;
  2941. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  2942. if (outstandingIrp->FileName!=NULL) {
  2943. AFD_FREE_POOL(
  2944. outstandingIrp,
  2945. AFD_DEBUG_POOL_TAG
  2946. );
  2947. }
  2948. return;
  2949. }
  2950. }
  2951. //
  2952. // The corresponding outstanding IRP structure was not found. This
  2953. // should never happen unless an allocate for an outstanding IRP
  2954. // structure failed above.
  2955. //
  2956. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  2957. "AfdCompleteOutstandingIrp: Irp %p not found on endpoint %p\n",
  2958. Irp, Endpoint ));
  2959. ASSERT( Endpoint->OutstandingIrpCount != 0 );
  2960. Endpoint->OutstandingIrpCount--;
  2961. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  2962. return;
  2963. } // AfdCompleteOutstandingIrpDebug
  2964. #endif
  2965. #if REFERENCE_DEBUG
  2966. AFD_QSPIN_LOCK AfdLocationTableLock;
  2967. PAFD_REFERENCE_LOCATION AfdLocationTable;
  2968. SIZE_T AfdLocationTableSize;
  2969. LONG AfdLocationId;
  2970. LONG
  2971. AfdFindReferenceLocation (
  2972. IN PCHAR Format,
  2973. OUT PLONG LocationId
  2974. )
  2975. {
  2976. AFD_LOCK_QUEUE_HANDLE lockHandle;
  2977. PVOID ignore;
  2978. AfdAcquireSpinLock (&AfdLocationTableLock, &lockHandle);
  2979. if (*LocationId==0) {
  2980. if (AfdLocationId >= (LONG)(AfdLocationTableSize/sizeof(AfdLocationTable[0]))) {
  2981. PAFD_REFERENCE_LOCATION newTable;
  2982. newTable = ExAllocatePoolWithTag (NonPagedPool,
  2983. AfdLocationTableSize+PAGE_SIZE,
  2984. AFD_DEBUG_POOL_TAG);
  2985. if (newTable!=NULL) {
  2986. if (AfdLocationTable!=NULL) {
  2987. RtlCopyMemory (newTable, AfdLocationTable, AfdLocationTableSize);
  2988. ExFreePoolWithTag (AfdLocationTable, AFD_DEBUG_POOL_TAG);
  2989. }
  2990. AfdLocationTable = newTable;
  2991. AfdLocationTableSize += PAGE_SIZE;
  2992. }
  2993. else {
  2994. goto Unlock;
  2995. }
  2996. }
  2997. AfdLocationTable[AfdLocationId].Format = Format;
  2998. RtlGetCallersAddress (&AfdLocationTable[AfdLocationId].Address, &ignore);
  2999. *LocationId = ++AfdLocationId;
  3000. }
  3001. Unlock:
  3002. AfdReleaseSpinLock (&AfdLocationTableLock, &lockHandle);
  3003. return *LocationId;
  3004. }
  3005. #endif
  3006. #if DBG || REFERENCE_DEBUG
  3007. VOID
  3008. AfdInitializeDebugData (
  3009. VOID
  3010. )
  3011. {
  3012. AfdInitializeSpinLock (&AfdLocationTableLock);
  3013. } // AfdInitializeDebugData
  3014. VOID
  3015. AfdFreeDebugData (
  3016. VOID
  3017. )
  3018. {
  3019. if (AfdLocationTable!=NULL) {
  3020. ExFreePoolWithTag (AfdLocationTable, AFD_DEBUG_POOL_TAG);
  3021. AfdLocationTable = NULL;
  3022. }
  3023. } // AfdFreeDebugData
  3024. #endif
  3025. #if DBG
  3026. ULONG AfdTotalAllocations = 0;
  3027. ULONG AfdTotalFrees = 0;
  3028. LARGE_INTEGER AfdTotalBytesAllocated;
  3029. LARGE_INTEGER AfdTotalBytesFreed;
  3030. PVOID
  3031. AfdAllocatePool (
  3032. IN POOL_TYPE PoolType,
  3033. IN SIZE_T NumberOfBytes,
  3034. IN ULONG Tag,
  3035. IN PCHAR FileName,
  3036. IN ULONG LineNumber,
  3037. IN BOOLEAN WithQuota,
  3038. IN EX_POOL_PRIORITY Priority
  3039. )
  3040. {
  3041. PVOID memBlock;
  3042. PAFD_POOL_HEADER header;
  3043. SIZE_T allocBytes;
  3044. //
  3045. // Check for overflow first.
  3046. //
  3047. if (NumberOfBytes+sizeof (*header)<=NumberOfBytes) {
  3048. if (WithQuota) {
  3049. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  3050. }
  3051. return NULL;
  3052. }
  3053. if (NumberOfBytes+sizeof (*header)>=PAGE_SIZE) {
  3054. allocBytes = NumberOfBytes;
  3055. if (allocBytes<PAGE_SIZE)
  3056. allocBytes = PAGE_SIZE;
  3057. }
  3058. else {
  3059. allocBytes = NumberOfBytes+sizeof (*header);
  3060. }
  3061. if ( WithQuota ) {
  3062. ASSERT (PoolType == (NonPagedPool|POOL_RAISE_IF_ALLOCATION_FAILURE) ||
  3063. PoolType == (PagedPool|POOL_RAISE_IF_ALLOCATION_FAILURE) ||
  3064. PoolType == (PagedPool|POOL_RAISE_IF_ALLOCATION_FAILURE|POOL_COLD_ALLOCATION));
  3065. memBlock = ExAllocatePoolWithQuotaTag(
  3066. PoolType,
  3067. allocBytes,
  3068. Tag
  3069. );
  3070. ASSERT (memBlock!=NULL);
  3071. } else {
  3072. ASSERT( PoolType == NonPagedPool ||
  3073. PoolType == NonPagedPoolMustSucceed ||
  3074. PoolType == PagedPool ||
  3075. PoolType == (PagedPool|POOL_COLD_ALLOCATION));
  3076. memBlock = ExAllocatePoolWithTagPriority(
  3077. PoolType,
  3078. allocBytes,
  3079. Tag,
  3080. Priority
  3081. );
  3082. if ( memBlock == NULL ) {
  3083. return NULL;
  3084. }
  3085. }
  3086. if (allocBytes<PAGE_SIZE) {
  3087. header = memBlock;
  3088. memBlock = header+1;
  3089. header->FileName = FileName;
  3090. header->LineNumber = LineNumber;
  3091. header->Size = NumberOfBytes;
  3092. header->InUse = PoolType;
  3093. }
  3094. else {
  3095. NumberOfBytes = PAGE_SIZE;
  3096. ASSERT (PAGE_ALIGN(memBlock)==memBlock);
  3097. }
  3098. ExInterlockedAddLargeStatistic(
  3099. &AfdTotalBytesAllocated,
  3100. (CLONG)NumberOfBytes
  3101. );
  3102. InterlockedIncrement(
  3103. &AfdTotalAllocations
  3104. );
  3105. return memBlock;
  3106. } // AfdAllocatePool
  3107. #define AFD_POOL_DEBUG 0
  3108. #if AFD_POOL_DEBUG
  3109. #define MAX_LRU_POOL_BLOCKS 256
  3110. PVOID AfdLRUPoolBlocks[MAX_LRU_POOL_BLOCKS];
  3111. LONG AfdLRUPoolIndex = -1;
  3112. #endif // AFD_POOL_DEBUG
  3113. VOID
  3114. AfdFreePool (
  3115. IN PVOID Pointer,
  3116. IN ULONG Tag
  3117. )
  3118. {
  3119. ULONG PoolType;
  3120. ULONG numberOfBytes;
  3121. if (PAGE_ALIGN (Pointer)==Pointer) {
  3122. numberOfBytes = PAGE_SIZE;
  3123. }
  3124. else {
  3125. PAFD_POOL_HEADER header;
  3126. Pointer = header = (PAFD_POOL_HEADER)Pointer - 1;
  3127. ASSERT (header->Size>0);
  3128. PoolType = InterlockedExchange (&header->InUse, -1);
  3129. ASSERT( PoolType == NonPagedPool ||
  3130. PoolType == NonPagedPoolMustSucceed ||
  3131. PoolType == PagedPool ||
  3132. PoolType == (NonPagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE) ||
  3133. PoolType == (PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE) ||
  3134. PoolType == (PagedPool | POOL_COLD_ALLOCATION) ||
  3135. PoolType == (PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE | POOL_COLD_ALLOCATION));
  3136. numberOfBytes = (CLONG)header->Size;
  3137. }
  3138. ExInterlockedAddLargeStatistic(
  3139. &AfdTotalBytesFreed,
  3140. numberOfBytes
  3141. );
  3142. InterlockedIncrement(
  3143. &AfdTotalFrees
  3144. );
  3145. #if AFD_POOL_DEBUG
  3146. {
  3147. LONG idx = InterlockedIncrement (&AfdLRUPoolIndex)%MAX_LRU_POOL_BLOCKS;
  3148. RtlFillMemoryUlong (
  3149. Pointer,
  3150. (numberOfBytes+3)&(~3),
  3151. Tag);
  3152. if (PoolType!=PagedPool) {
  3153. ULONG size;
  3154. Pointer = InterlockedExchangePointer (
  3155. &AfdLRUPoolBlocks[idx],
  3156. Pointer);
  3157. if (Pointer==NULL)
  3158. return;
  3159. if (PAGE_ALIGN(Pointer)==Pointer)
  3160. numberOfBytes = PAGE_SIZE;
  3161. else {
  3162. PAFD_HEADER header;
  3163. header = (PAFD_POOL_HEADER)Pointer - 1;
  3164. Tag = *((PULONG)Pointer);
  3165. numberOfBytes = (CLONG)(header->Size+3)&(~3);
  3166. }
  3167. size = RtlCompareMemoryUlong (Pointer, numberOfBytes, Tag);
  3168. if (size!=numberOfBytes) {
  3169. DbgPrint ("Block %p is modified at %p after it was freed.\n",
  3170. Pointer, (PUCHAR)Pointer+size);
  3171. DbgBreakPoint ();
  3172. }
  3173. }
  3174. }
  3175. #endif AFD_POOL_DEBUG
  3176. MyFreePoolWithTag(
  3177. (PVOID)Pointer,
  3178. Tag
  3179. );
  3180. } // AfdFreePool
  3181. #ifdef AFDDBG_QUOTA
  3182. typedef struct _AFD_QUOTA_HASH {
  3183. PSZ Type;
  3184. LONG TotalAmount;
  3185. } AFD_QUOTA_HASH, *PAFD_QUOTA_HASH;
  3186. #define AFD_QUOTA_HASH_SIZE 31
  3187. AFD_QUOTA_HASH AfdQuotaHash[AFD_QUOTA_HASH_SIZE];
  3188. PEPROCESS AfdQuotaProcess;
  3189. typedef struct {
  3190. union {
  3191. ULONG Bytes;
  3192. struct {
  3193. UCHAR Reserved[3];
  3194. UCHAR Sign;
  3195. } ;
  3196. } ;
  3197. UCHAR Location[12];
  3198. PVOID Block;
  3199. PVOID Process;
  3200. PVOID Reserved2[2];
  3201. } QUOTA_HISTORY, *PQUOTA_HISTORY;
  3202. #define QUOTA_HISTORY_LENGTH 512
  3203. QUOTA_HISTORY AfdQuotaHistory[QUOTA_HISTORY_LENGTH];
  3204. LONG AfdQuotaHistoryIndex = 0;
  3205. VOID
  3206. AfdRecordQuotaHistory(
  3207. IN PEPROCESS Process,
  3208. IN LONG Bytes,
  3209. IN PSZ Type,
  3210. IN PVOID Block
  3211. )
  3212. {
  3213. LONG index;
  3214. PQUOTA_HISTORY history;
  3215. index = InterlockedIncrement( &AfdQuotaHistoryIndex );
  3216. index &= QUOTA_HISTORY_LENGTH - 1;
  3217. history = &AfdQuotaHistory[index];
  3218. history->Bytes = Bytes;
  3219. history->Sign = Bytes < 0 ? '-' : '+';
  3220. RtlCopyMemory( history->Location, Type, 12 );
  3221. history->Block = Block;
  3222. history->Process = Process;
  3223. index = (ULONG_PTR)Type % AFD_QUOTA_HASH_SIZE;
  3224. if (AfdQuotaHash[index].Type!=Type) {
  3225. if (InterlockedCompareExchangePointer (
  3226. (PVOID *)&AfdQuotaHash[index].Type,
  3227. Type,
  3228. NULL)!=NULL) {
  3229. AfdQuotaHash[index].Type = (PVOID)-1;
  3230. }
  3231. }
  3232. InterlockedExchangeAdd (&AfdQuotaHash[index].TotalAmount, Bytes);
  3233. } // AfdRecordQuotaHistory
  3234. #endif
  3235. #endif
  3236. PMDL
  3237. AfdAdvanceMdlChain(
  3238. IN PMDL Mdl,
  3239. IN ULONG Offset
  3240. )
  3241. /*++
  3242. Routine Description:
  3243. Accepts a pointer to an existing MDL chain and offsets that chain
  3244. by a specified number of bytes. This may involve the creation
  3245. of a partial MDL for the first entry in the new chain.
  3246. Arguments:
  3247. Mdl - Pointer to the MDL chain to advance.
  3248. Offset - The number of bytes to offset the chain.
  3249. Return Value:
  3250. NTSTATUS -- Indicates the status of the request.
  3251. --*/
  3252. {
  3253. //
  3254. // Sanity check.
  3255. //
  3256. ASSERT( Mdl != NULL );
  3257. ASSERT( Offset > 0 );
  3258. //
  3259. // Scan past any fully completed MDLs.
  3260. //
  3261. while ( Offset > MmGetMdlByteCount( Mdl ) ) {
  3262. PMDL prev = Mdl;
  3263. Offset -= MmGetMdlByteCount( Mdl );
  3264. ASSERT( Mdl->Next != NULL );
  3265. Mdl = Mdl->Next;
  3266. prev->Next = NULL;
  3267. MmUnlockPages (prev);
  3268. IoFreeMdl (prev);
  3269. }
  3270. //
  3271. // Tautology of the day: Offset will either be zero (meaning that
  3272. // we've advanced to a clean boundary between MDLs) or non-zero
  3273. // (meaning we need to now build a partial MDL).
  3274. //
  3275. if ( Offset > 0 ) {
  3276. NTSTATUS status;
  3277. //
  3278. // Use new MM routine.
  3279. // This saves us use of MustSucceed pool since the routine
  3280. // below is guaranteed to succeed (as it should because
  3281. // we already have the whole range locked and possibly mapped
  3282. // and there should be no problem extracting part of it within
  3283. // the same MDL).
  3284. //
  3285. status = MmAdvanceMdl (Mdl, Offset);
  3286. ASSERT (status==STATUS_SUCCESS);
  3287. }
  3288. return Mdl;
  3289. } // AfdAdvanceMdlChain
  3290. NTSTATUS
  3291. AfdAllocateMdlChain(
  3292. IN PIRP Irp,
  3293. IN LPWSABUF BufferArray,
  3294. IN ULONG BufferCount,
  3295. IN LOCK_OPERATION Operation,
  3296. OUT PULONG TotalByteCount
  3297. )
  3298. /*++
  3299. Routine Description:
  3300. Allocates a MDL chain describing the WSABUF array and attaches
  3301. the chain to the specified IRP.
  3302. Arguments:
  3303. Irp - The IRP that will receive the MDL chain.
  3304. BufferArray - Points to an array of WSABUF structures describing
  3305. the user's buffers.
  3306. BufferCount - Contains the number of WSABUF structures in the
  3307. array.
  3308. Operation - Specifies the type of operation being performed (either
  3309. IoReadAccess or IoWriteAccess).
  3310. TotalByteCount - Will receive the total number of BYTEs described
  3311. by the WSABUF array.
  3312. Return Value:
  3313. NTSTATUS -- Indicates the status of the request.
  3314. --*/
  3315. {
  3316. NTSTATUS status;
  3317. PMDL currentMdl;
  3318. PMDL * chainTarget;
  3319. KPROCESSOR_MODE previousMode;
  3320. ULONG totalLength;
  3321. PVOID bufferPointer;
  3322. ULONG bufferLength;
  3323. //
  3324. // Sanity check.
  3325. //
  3326. ASSERT( Irp != NULL );
  3327. ASSERT( Irp->MdlAddress == NULL );
  3328. ASSERT( ( Operation == IoReadAccess ) || ( Operation == IoWriteAccess ) );
  3329. ASSERT( TotalByteCount != NULL );
  3330. //
  3331. // Get the previous processor mode.
  3332. //
  3333. previousMode = Irp->RequestorMode;
  3334. //
  3335. // Get into a known state.
  3336. //
  3337. status = STATUS_SUCCESS;
  3338. currentMdl = NULL;
  3339. chainTarget = &Irp->MdlAddress;
  3340. totalLength = 0;
  3341. //
  3342. // Walk the array of WSABUF structures, creating the MDLs and
  3343. // probing & locking the pages.
  3344. //
  3345. try {
  3346. if( previousMode != KernelMode ) {
  3347. if ((BufferArray==NULL) ||
  3348. (BufferCount==0) ||
  3349. (BufferCount>(MAXULONG/sizeof (WSABUF)))) {
  3350. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3351. }
  3352. //
  3353. // Probe the WSABUF array.
  3354. //
  3355. ProbeForRead(
  3356. BufferArray, // Address
  3357. BufferCount * sizeof(WSABUF), // Length
  3358. PROBE_ALIGNMENT(WSABUF) // Alignment
  3359. );
  3360. }
  3361. else {
  3362. ASSERT( BufferArray != NULL );
  3363. ASSERT( BufferCount > 0 );
  3364. }
  3365. //
  3366. // Scan the array.
  3367. //
  3368. for ( ; BufferCount>0; BufferCount--, BufferArray++) {
  3369. bufferPointer = BufferArray->buf;
  3370. bufferLength = BufferArray->len;
  3371. if( bufferLength > 0 ) {
  3372. //
  3373. // Update the total byte counter.
  3374. //
  3375. totalLength += bufferLength;
  3376. //
  3377. // Create a new MDL.
  3378. //
  3379. currentMdl = IoAllocateMdl(
  3380. bufferPointer, // VirtualAddress
  3381. bufferLength, // Length
  3382. FALSE, // SecondaryBuffer
  3383. TRUE, // ChargeQuota
  3384. NULL // Irp
  3385. );
  3386. if( currentMdl != NULL ) {
  3387. //
  3388. // Lock the pages. This will raise an exception
  3389. // if the operation fails.
  3390. //
  3391. MmProbeAndLockPages(
  3392. currentMdl, // MemoryDescriptorList
  3393. previousMode, // AccessMode
  3394. Operation // Operation
  3395. );
  3396. //
  3397. // Chain the MDL onto the IRP. In theory, we could
  3398. // do this by passing the IRP into IoAllocateMdl(),
  3399. // but IoAllocateMdl() does a linear scan on the MDL
  3400. // chain to find the last one in the chain.
  3401. //
  3402. // We can do much better.
  3403. //
  3404. *chainTarget = currentMdl;
  3405. chainTarget = &currentMdl->Next;
  3406. } else {
  3407. //
  3408. // Cannot allocate new MDL, return appropriate error.
  3409. //
  3410. status = STATUS_INSUFFICIENT_RESOURCES;
  3411. break;
  3412. }
  3413. }
  3414. }
  3415. //
  3416. // Ensure the MDL chain is NULL terminated.
  3417. //
  3418. ASSERT( *chainTarget == NULL );
  3419. } except( AFD_EXCEPTION_FILTER(&status) ) {
  3420. //
  3421. // currentMdl will only be non-NULL at this point if an MDL
  3422. // has been created, but MmProbeAndLockPages() raised an
  3423. // exception. If this is true, then free the MDL.
  3424. // Also account for the case when currentMdl has been linked
  3425. // onto the chain and exception occured when accesing next user
  3426. // buffer.
  3427. //
  3428. if( currentMdl != NULL && chainTarget!=&currentMdl->Next) {
  3429. IoFreeMdl( currentMdl );
  3430. }
  3431. }
  3432. //
  3433. // Return the total buffer count.
  3434. //
  3435. *TotalByteCount = totalLength;
  3436. return status;
  3437. } // AfdAllocateMdlChain
  3438. #ifdef _WIN64
  3439. NTSTATUS
  3440. AfdAllocateMdlChain32(
  3441. IN PIRP Irp,
  3442. IN LPWSABUF32 BufferArray,
  3443. IN ULONG BufferCount,
  3444. IN LOCK_OPERATION Operation,
  3445. OUT PULONG TotalByteCount
  3446. )
  3447. /*++
  3448. Routine Description:
  3449. Allocates a MDL chain describing the WSABUF array and attaches
  3450. the chain to the specified IRP.
  3451. Arguments:
  3452. Irp - The IRP that will receive the MDL chain.
  3453. BufferArray - Points to an array of WSABUF structures describing
  3454. the user's buffers.
  3455. BufferCount - Contains the number of WSABUF structures in the
  3456. array.
  3457. Operation - Specifies the type of operation being performed (either
  3458. IoReadAccess or IoWriteAccess).
  3459. TotalByteCount - Will receive the total number of BYTEs described
  3460. by the WSABUF array.
  3461. Return Value:
  3462. NTSTATUS -- Indicates the status of the request.
  3463. --*/
  3464. {
  3465. NTSTATUS status;
  3466. PMDL currentMdl;
  3467. PMDL * chainTarget;
  3468. KPROCESSOR_MODE previousMode;
  3469. ULONG totalLength;
  3470. PVOID bufferPointer;
  3471. ULONG bufferLength;
  3472. //
  3473. // Sanity check.
  3474. //
  3475. ASSERT( Irp != NULL );
  3476. ASSERT( Irp->MdlAddress == NULL );
  3477. ASSERT( ( Operation == IoReadAccess ) || ( Operation == IoWriteAccess ) );
  3478. ASSERT( TotalByteCount != NULL );
  3479. //
  3480. // Get the previous processor mode.
  3481. //
  3482. previousMode = Irp->RequestorMode;
  3483. //
  3484. // Get into a known state.
  3485. //
  3486. status = STATUS_SUCCESS;
  3487. currentMdl = NULL;
  3488. chainTarget = &Irp->MdlAddress;
  3489. totalLength = 0;
  3490. //
  3491. // Walk the array of WSABUF structures, creating the MDLs and
  3492. // probing & locking the pages.
  3493. //
  3494. try {
  3495. if( previousMode != KernelMode ) {
  3496. if ((BufferArray==NULL) ||
  3497. (BufferCount==0) ||
  3498. (BufferCount>(MAXULONG/sizeof (WSABUF32)))) {
  3499. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  3500. }
  3501. //
  3502. // Probe the WSABUF array.
  3503. //
  3504. ProbeForRead(
  3505. BufferArray, // Address
  3506. BufferCount * sizeof(WSABUF32), // Length
  3507. PROBE_ALIGNMENT32(WSABUF32) // Alignment
  3508. );
  3509. }
  3510. else {
  3511. ASSERT( BufferArray != NULL );
  3512. ASSERT( BufferCount > 0 );
  3513. }
  3514. //
  3515. // Scan the array.
  3516. //
  3517. for ( ; BufferCount>0; BufferCount--, BufferArray++) {
  3518. bufferPointer = BufferArray->buf;
  3519. bufferLength = BufferArray->len;
  3520. if( bufferLength > 0 ) {
  3521. //
  3522. // Update the total byte counter.
  3523. //
  3524. totalLength += bufferLength;
  3525. //
  3526. // Create a new MDL.
  3527. //
  3528. currentMdl = IoAllocateMdl(
  3529. bufferPointer, // VirtualAddress
  3530. bufferLength, // Length
  3531. FALSE, // SecondaryBuffer
  3532. TRUE, // ChargeQuota
  3533. NULL // Irp
  3534. );
  3535. if( currentMdl != NULL ) {
  3536. //
  3537. // Lock the pages. This will raise an exception
  3538. // if the operation fails.
  3539. //
  3540. MmProbeAndLockPages(
  3541. currentMdl, // MemoryDescriptorList
  3542. previousMode, // AccessMode
  3543. Operation // Operation
  3544. );
  3545. //
  3546. // Chain the MDL onto the IRP. In theory, we could
  3547. // do this by passing the IRP into IoAllocateMdl(),
  3548. // but IoAllocateMdl() does a linear scan on the MDL
  3549. // chain to find the last one in the chain.
  3550. //
  3551. // We can do much better.
  3552. //
  3553. *chainTarget = currentMdl;
  3554. chainTarget = &currentMdl->Next;
  3555. } else {
  3556. //
  3557. // Cannot allocate new MDL, return appropriate error.
  3558. //
  3559. status = STATUS_INSUFFICIENT_RESOURCES;
  3560. break;
  3561. }
  3562. }
  3563. }
  3564. //
  3565. // Ensure the MDL chain is NULL terminated.
  3566. //
  3567. ASSERT( *chainTarget == NULL );
  3568. } except( AFD_EXCEPTION_FILTER(&status) ) {
  3569. //
  3570. // currentMdl will only be non-NULL at this point if an MDL
  3571. // has been created, but MmProbeAndLockPages() raised an
  3572. // exception. If this is true, then free the MDL.
  3573. // Also account for the case when currentMdl has been linked
  3574. // onto the chain and exception occured when accesing next user
  3575. // buffer.
  3576. //
  3577. if( currentMdl != NULL && chainTarget!=&currentMdl->Next) {
  3578. IoFreeMdl( currentMdl );
  3579. }
  3580. }
  3581. //
  3582. // Return the total buffer count.
  3583. //
  3584. *TotalByteCount = totalLength;
  3585. return status;
  3586. } // AfdAllocateMdlChain32
  3587. #endif //_WIN64
  3588. VOID
  3589. AfdDestroyMdlChain (
  3590. IN PIRP Irp
  3591. )
  3592. /*++
  3593. Routine Description:
  3594. Unlocks & frees the MDLs in the MDL chain attached to the given IRP.
  3595. Arguments:
  3596. Irp - The IRP that owns the MDL chain to destroy.
  3597. Return Value:
  3598. None.
  3599. --*/
  3600. {
  3601. PMDL mdl;
  3602. PMDL nextMdl;
  3603. mdl = Irp->MdlAddress;
  3604. Irp->MdlAddress = NULL;
  3605. while( mdl != NULL ) {
  3606. nextMdl = mdl->Next;
  3607. MmUnlockPages( mdl );
  3608. IoFreeMdl( mdl );
  3609. mdl = nextMdl;
  3610. }
  3611. } // AfdDestroyMdlChain
  3612. ULONG
  3613. AfdCalcBufferArrayByteLength(
  3614. IN LPWSABUF BufferArray,
  3615. IN ULONG BufferCount
  3616. )
  3617. /*++
  3618. Routine Description:
  3619. Calculates the total size (in bytes) of the buffers described by the
  3620. specified WSABUF array.
  3621. Arguments:
  3622. BufferArray - Points to an array of WSABUF structures.
  3623. BufferCount - The number of entries in BufferArray.
  3624. Return Value:
  3625. ULONG - The total size (in bytes) of the buffers described by the
  3626. WSABUF array. Will raise an exception & return -1 if the total
  3627. size is obviously too large.
  3628. --*/
  3629. {
  3630. LARGE_INTEGER totalLength;
  3631. PAGED_CODE( );
  3632. //
  3633. // Sanity check.
  3634. //
  3635. ASSERT( BufferArray != NULL );
  3636. ASSERT( BufferCount > 0 );
  3637. ASSERT( BufferCount <= (MAXULONG/sizeof (WSABUF)));
  3638. //
  3639. // Scan the array & sum the lengths.
  3640. //
  3641. totalLength.QuadPart = 0;
  3642. while( BufferCount-- ) {
  3643. totalLength.QuadPart += (LONGLONG)BufferArray->len;
  3644. BufferArray++;
  3645. }
  3646. if( totalLength.HighPart != 0 ||
  3647. ( totalLength.LowPart & 0x80000000 ) != 0 ) {
  3648. ExRaiseAccessViolation();
  3649. }
  3650. return totalLength.LowPart;
  3651. } // AfdCalcBufferArrayByteLength
  3652. ULONG
  3653. AfdCopyBufferArrayToBuffer(
  3654. IN PVOID Destination,
  3655. IN ULONG DestinationLength,
  3656. IN LPWSABUF BufferArray,
  3657. IN ULONG BufferCount
  3658. )
  3659. /*++
  3660. Routine Description:
  3661. Copies data from a WSABUF array to a linear buffer.
  3662. Arguments:
  3663. Destination - Points to the linear destination of the data.
  3664. DestinationLength - The length of Destination.
  3665. BufferArray - Points to an array of WSABUF structures describing the
  3666. source for the copy.
  3667. BufferCount - The number of entries in BufferArray.
  3668. Return Value:
  3669. ULONG - The number of bytes copied.
  3670. --*/
  3671. {
  3672. PVOID destinationStart;
  3673. ULONG bytesToCopy;
  3674. PAGED_CODE( );
  3675. //
  3676. // Sanity check.
  3677. //
  3678. ASSERT( Destination != NULL );
  3679. ASSERT( BufferArray != NULL );
  3680. ASSERT( BufferCount > 0 );
  3681. //
  3682. // Remember this so we can calc number of bytes copied.
  3683. //
  3684. destinationStart = Destination;
  3685. //
  3686. // Scan the array & copy to the linear buffer.
  3687. //
  3688. while( BufferCount-- && DestinationLength > 0 ) {
  3689. WSABUF Buffer = *BufferArray++;
  3690. bytesToCopy = min( DestinationLength, Buffer.len );
  3691. if( ExGetPreviousMode() != KernelMode ) {
  3692. ProbeForRead(
  3693. Buffer.buf, // Address
  3694. bytesToCopy, // Length
  3695. sizeof(UCHAR) // Alignment
  3696. );
  3697. }
  3698. RtlCopyMemory(
  3699. Destination,
  3700. Buffer.buf,
  3701. bytesToCopy
  3702. );
  3703. Destination = (PCHAR)Destination + bytesToCopy;
  3704. DestinationLength -= bytesToCopy;
  3705. }
  3706. //
  3707. // Return number of bytes copied.
  3708. //
  3709. return (ULONG)((PUCHAR)Destination - (PUCHAR)destinationStart);
  3710. } // AfdCopyBufferArrayToBuffer
  3711. ULONG
  3712. AfdCopyBufferToBufferArray(
  3713. IN LPWSABUF BufferArray,
  3714. IN ULONG Offset,
  3715. IN ULONG BufferCount,
  3716. IN PVOID Source,
  3717. IN ULONG SourceLength
  3718. )
  3719. /*++
  3720. Routine Description:
  3721. Copies data from a linear buffer to a WSABUF array.
  3722. Arguments:
  3723. BufferArray - Points to an array of WSABUF structures describing the
  3724. destination for the copy.
  3725. Offset - An offset within the buffer array at which the data should
  3726. be copied.
  3727. BufferCount - The number of entries in BufferArray.
  3728. Source - Points to the linear source of the data.
  3729. SourceLength - The length of Source.
  3730. Return Value:
  3731. ULONG - The number of bytes copied.
  3732. --*/
  3733. {
  3734. PVOID sourceStart;
  3735. ULONG bytesToCopy;
  3736. WSABUF buffer;
  3737. PAGED_CODE( );
  3738. //
  3739. // Sanity check.
  3740. //
  3741. ASSERT( BufferArray != NULL );
  3742. ASSERT( BufferCount > 0 );
  3743. ASSERT( Source != NULL );
  3744. ASSERT( SourceLength > 0 );
  3745. //
  3746. // Remember this so we can return the number of bytes copied.
  3747. //
  3748. sourceStart = Source;
  3749. //
  3750. // Handle the offset if one was specified.
  3751. //
  3752. if( Offset > 0 ) {
  3753. //
  3754. // Skip whole entries if necessary.
  3755. //
  3756. while( BufferCount > 0 &&
  3757. (buffer=*BufferArray++, Offset >= buffer.len) ) {
  3758. Offset -= buffer.len;
  3759. BufferCount--;
  3760. }
  3761. if( BufferCount > 0 ) {
  3762. //
  3763. // If we have buffers left, fix up the buffer pointer
  3764. // and length to keep the loop below fast.
  3765. //
  3766. ASSERT( Offset < buffer.len );
  3767. buffer.buf += Offset;
  3768. buffer.len -= Offset;
  3769. //
  3770. // We have already copied buffer array element, so jump
  3771. // to the body of the loop to avoid doing this again (this
  3772. // is not a mere optimization, but protection from application
  3773. // that plays tricks on us by changing content of the buffer
  3774. // array while we are looking at it).
  3775. //
  3776. goto DoCopy;
  3777. }
  3778. }
  3779. //
  3780. // Scan the array & copy from the linear buffer.
  3781. //
  3782. while( BufferCount-->0 && SourceLength > 0 ) {
  3783. buffer = *BufferArray++;
  3784. DoCopy:
  3785. bytesToCopy = min( SourceLength, buffer.len );
  3786. if( ExGetPreviousMode() != KernelMode ) {
  3787. ProbeForWrite(
  3788. buffer.buf, // Address
  3789. bytesToCopy, // Length
  3790. sizeof(UCHAR) // Alignment
  3791. );
  3792. }
  3793. RtlCopyMemory(
  3794. buffer.buf,
  3795. Source,
  3796. bytesToCopy
  3797. );
  3798. Source = (PCHAR)Source + bytesToCopy;
  3799. SourceLength -= bytesToCopy;
  3800. }
  3801. //
  3802. // Return number of bytes copied.
  3803. //
  3804. return (ULONG)((PUCHAR)Source - (PUCHAR)sourceStart);
  3805. } // AfdCopyBufferToBufferArray
  3806. ULONG
  3807. AfdCopyMdlChainToBufferArray(
  3808. IN LPWSABUF BufferArray,
  3809. IN ULONG BufferOffset,
  3810. IN ULONG BufferCount,
  3811. IN PMDL SourceMdl,
  3812. IN ULONG SourceOffset,
  3813. IN ULONG SourceLength
  3814. )
  3815. /*++
  3816. Routine Description:
  3817. Copies data from a MDL chain to a WSABUF array.
  3818. Arguments:
  3819. BufferArray - Points to an array of WSABUF structures describing the
  3820. destination for the copy.
  3821. BufferOffset - An offset within the buffer array at which the data should
  3822. be copied.
  3823. BufferCount - The number of entries in BufferArray.
  3824. Source - Points to the MDL chain with data
  3825. SourceOffset - An offset within the MDL chain from which the data should
  3826. be copied.
  3827. SourceLength - The length of Source.
  3828. Return Value:
  3829. ULONG - The number of bytes copied.
  3830. --*/
  3831. {
  3832. ULONG bytesCopied;
  3833. ULONG bytesToCopy, len;
  3834. WSABUF buffer;
  3835. PAGED_CODE( );
  3836. //
  3837. // Assume we can copy everything.
  3838. //
  3839. bytesCopied = SourceLength;
  3840. //
  3841. // Sanity check.
  3842. //
  3843. ASSERT( BufferArray != NULL );
  3844. ASSERT( BufferCount > 0 );
  3845. ASSERT( SourceMdl != NULL );
  3846. ASSERT( SourceLength>0 );
  3847. //
  3848. // Skip offset into the MDL chain
  3849. //
  3850. while (SourceOffset>=MmGetMdlByteCount (SourceMdl)) {
  3851. SourceOffset -= MmGetMdlByteCount (SourceMdl);
  3852. SourceMdl = SourceMdl->Next;
  3853. }
  3854. //
  3855. // Handle buffer array offset if specified
  3856. //
  3857. if (BufferOffset>0) {
  3858. //
  3859. // Skip whole entries.
  3860. //
  3861. while( BufferCount > 0 &&
  3862. (buffer=*BufferArray++,BufferOffset >= buffer.len) ) {
  3863. BufferOffset -= buffer.len;
  3864. BufferCount--;
  3865. }
  3866. if( BufferCount>0 ) {
  3867. //
  3868. // If we have buffers left, fix up the buffer pointer
  3869. // and length to keep the loop below fast.
  3870. //
  3871. ASSERT (BufferOffset < buffer.len);
  3872. buffer.buf += BufferOffset;
  3873. buffer.len -= BufferOffset;
  3874. //
  3875. // We have already copied buffer array element, so jump
  3876. // to the body of the loop to avoid doing this again (this
  3877. // is not a mere optimization, but protection from application
  3878. // that plays tricks on us by changing content of the buffer
  3879. // array while we are looking at it).
  3880. //
  3881. goto DoCopy;
  3882. }
  3883. }
  3884. //
  3885. // Scan the array & copy from the mdl chain.
  3886. //
  3887. while (SourceLength>0 && BufferCount-->0) {
  3888. buffer = *BufferArray++;
  3889. DoCopy:
  3890. bytesToCopy = min( SourceLength, buffer.len );
  3891. if( ExGetPreviousMode() != KernelMode ) {
  3892. ProbeForWrite(
  3893. buffer.buf, // Address
  3894. bytesToCopy, // Length
  3895. sizeof(UCHAR) // Alignment
  3896. );
  3897. }
  3898. //
  3899. // Update source length for data we are going to copy
  3900. //
  3901. SourceLength -= bytesToCopy;
  3902. //
  3903. // Copy full source MDLs
  3904. //
  3905. while (bytesToCopy>0 &&
  3906. (bytesToCopy>=(len=MmGetMdlByteCount (SourceMdl)-SourceOffset))) {
  3907. ASSERT (SourceMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL));
  3908. RtlCopyMemory (buffer.buf,
  3909. (PUCHAR)MmGetSystemAddressForMdl(SourceMdl)+SourceOffset,
  3910. len);
  3911. bytesToCopy -= len;
  3912. buffer.buf += len;
  3913. SourceMdl = SourceMdl->Next;
  3914. SourceOffset = 0;
  3915. }
  3916. //
  3917. // Copy partial source MDL if space remains.
  3918. //
  3919. if (bytesToCopy>0) {
  3920. ASSERT (bytesToCopy<MmGetMdlByteCount (SourceMdl)-SourceOffset);
  3921. ASSERT (SourceMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL));
  3922. RtlCopyMemory (buffer.buf,
  3923. (PUCHAR)MmGetSystemAddressForMdl (SourceMdl)+SourceOffset,
  3924. bytesToCopy
  3925. );
  3926. SourceOffset += bytesToCopy;
  3927. }
  3928. }
  3929. //
  3930. // Return number of bytes copied except for those we couldn't.
  3931. //
  3932. return bytesCopied-SourceLength;
  3933. } // AfdCopyMdlChainToBufferArray
  3934. NTSTATUS
  3935. AfdCopyMdlChainToBufferAvoidMapping(
  3936. IN PMDL SrcMdl,
  3937. IN ULONG SrcOffset,
  3938. IN ULONG SrcLength,
  3939. IN PUCHAR Dst,
  3940. IN ULONG DstSize
  3941. )
  3942. /*++
  3943. Routine Description:
  3944. Copies data from a MDL chain to a buffer and avoids mapping
  3945. MDLs to system space if possible.
  3946. Arguments:
  3947. Dst - Points to destination for the copy.
  3948. DstSize - Size of the buffer
  3949. Source - Points to the MDL chain with data
  3950. SourceOffset - An offset within the MDL chain from which the data should
  3951. be copied.
  3952. SourceLength - The length of Source.
  3953. Return Value:
  3954. NTSTATUS - success if everything was copied OK
  3955. STATUS_INSUFFICIENT_RESOURCES - mapping failed
  3956. --*/
  3957. {
  3958. NTSTATUS status = STATUS_SUCCESS;
  3959. ULONG bytesToCopy;
  3960. PUCHAR DstEnd = Dst+DstSize;
  3961. PAGED_CODE( );
  3962. //
  3963. // Sanity check.
  3964. //
  3965. ASSERT( Dst != NULL );
  3966. ASSERT( DstSize > 0 );
  3967. ASSERT( SrcMdl != NULL );
  3968. ASSERT( SrcLength>0 );
  3969. //
  3970. // Skip offset into the MDL chain
  3971. //
  3972. while (SrcOffset>=MmGetMdlByteCount (SrcMdl)) {
  3973. SrcOffset -= MmGetMdlByteCount (SrcMdl);
  3974. SrcMdl = SrcMdl->Next;
  3975. }
  3976. while (Dst<DstEnd) {
  3977. //
  3978. // Determine how much we can copy and m
  3979. // ake sure not to exceed limits.
  3980. //
  3981. bytesToCopy = MmGetMdlByteCount(SrcMdl)-SrcOffset;
  3982. ASSERT (bytesToCopy<=(ULONG)(DstEnd-Dst));
  3983. if (bytesToCopy>SrcLength) {
  3984. bytesToCopy = SrcLength;
  3985. }
  3986. if (SrcMdl->Process==IoGetCurrentProcess ()) {
  3987. //
  3988. // If we are in the context of the same process that
  3989. // MDL was created for, copy using VAs.
  3990. //
  3991. try {
  3992. RtlCopyMemory (
  3993. Dst,
  3994. (PUCHAR)MmGetMdlVirtualAddress (SrcMdl)+SrcOffset,
  3995. bytesToCopy
  3996. );
  3997. }
  3998. except (AFD_EXCEPTION_FILTER (&status)) {
  3999. return status;
  4000. }
  4001. }
  4002. else {
  4003. //
  4004. // Otherwise, map MDL into the system space.
  4005. //
  4006. PCHAR src = MmGetSystemAddressForMdlSafe (SrcMdl, LowPagePriority);
  4007. if (!src)
  4008. return STATUS_INSUFFICIENT_RESOURCES;
  4009. RtlCopyMemory (
  4010. Dst,
  4011. src+SrcOffset,
  4012. bytesToCopy
  4013. );
  4014. }
  4015. //
  4016. // Update source length for data we are going to copy
  4017. //
  4018. SrcLength -= bytesToCopy;
  4019. if (SrcLength==0)
  4020. return STATUS_SUCCESS;
  4021. SrcMdl = SrcMdl->Next;
  4022. SrcOffset = 0;
  4023. Dst += bytesToCopy;
  4024. }
  4025. return STATUS_BUFFER_OVERFLOW;
  4026. } // AfdCopyMdlChainToBufferAvoidMapping
  4027. NTSTATUS
  4028. AfdMapMdlChain (
  4029. PMDL MdlChain
  4030. )
  4031. /*++
  4032. Routine Description:
  4033. Makes sure that eveyr MDL in the chains is mapped into
  4034. the system address space.
  4035. Arguments:
  4036. MdlChain - Destination MDL.
  4037. Return Value:
  4038. STATUS_SUCCESS - MDL chain is fully mapped
  4039. STATUS_INSUFFICIENT_RESOURCES - at least one MDL could not be mapped
  4040. --*/
  4041. {
  4042. while (MdlChain!=NULL) {
  4043. if (MmGetSystemAddressForMdlSafe(MdlChain, LowPagePriority)==NULL) {
  4044. return STATUS_INSUFFICIENT_RESOURCES;
  4045. }
  4046. MdlChain = MdlChain->Next;
  4047. }
  4048. return STATUS_SUCCESS;
  4049. } // AfdMapMdlChain
  4050. NTSTATUS
  4051. AfdCopyMdlChainToMdlChain (
  4052. PMDL DstMdl,
  4053. ULONG DstOffset,
  4054. PMDL SrcMdl,
  4055. ULONG SrcOffset,
  4056. ULONG SrcLength,
  4057. PULONG BytesCopied
  4058. )
  4059. /*++
  4060. Routine Description:
  4061. Copies data from an MDL chain to an MDL chain.
  4062. Arguments:
  4063. DstMdl - Destination MDL.
  4064. DstOffset - Offset withih the destination MDL.
  4065. SrcMdl - Source MDL.
  4066. SrcOffset - Offset within the source.
  4067. SrcLength - lenght of the data in the source chain
  4068. BytesCopied - points to variable that received total number
  4069. of bytes actually copied
  4070. Return Value:
  4071. STATUS_SUCCESS - all of the source data was copied
  4072. STATUS_BUFFER_OVERFLOW - destination MDL was not long enough
  4073. to hold all of the source data.
  4074. --*/
  4075. {
  4076. ULONG bytesToCopy = 0, len;
  4077. PUCHAR dst;
  4078. ASSERT( SrcMdl != NULL );
  4079. ASSERT( DstMdl != NULL );
  4080. //
  4081. // Assume we can copy everything.
  4082. //
  4083. *BytesCopied = SrcLength;
  4084. //
  4085. // Skip full MDLs in source.
  4086. //
  4087. while ((SrcMdl!=NULL) && (SrcOffset>=MmGetMdlByteCount (SrcMdl))) {
  4088. SrcOffset -= MmGetMdlByteCount (SrcMdl);
  4089. SrcMdl = SrcMdl->Next;
  4090. }
  4091. //
  4092. // Skip full MDLs in destination
  4093. //
  4094. while ((DstMdl!=NULL) && (DstOffset>=MmGetMdlByteCount (DstMdl))) {
  4095. DstOffset -= MmGetMdlByteCount (DstMdl);
  4096. DstMdl = DstMdl->Next;
  4097. }
  4098. //
  4099. // Handle remaining destination offset separately to simplify the main loop.
  4100. //
  4101. if (DstOffset>0) {
  4102. dst = MmGetSystemAddressForMdlSafe (DstMdl, LowPagePriority);
  4103. if (dst==NULL)
  4104. return STATUS_INSUFFICIENT_RESOURCES;
  4105. dst += DstOffset;
  4106. bytesToCopy = MmGetMdlByteCount(DstMdl)-DstOffset;
  4107. goto DoCopy;
  4108. }
  4109. //
  4110. // For each MDL in destination copy source MDLs
  4111. // while source data and free space in destination remain
  4112. //
  4113. while ((SrcLength>0) && (DstMdl!=NULL)) {
  4114. dst = MmGetSystemAddressForMdlSafe (DstMdl, LowPagePriority);
  4115. if (dst==NULL)
  4116. return STATUS_INSUFFICIENT_RESOURCES;
  4117. bytesToCopy = MmGetMdlByteCount(DstMdl);
  4118. DoCopy:
  4119. bytesToCopy = min (SrcLength, bytesToCopy);
  4120. //
  4121. // Adjust source length
  4122. //
  4123. SrcLength -= bytesToCopy;
  4124. //
  4125. // Copy full source MDLs
  4126. //
  4127. while (bytesToCopy>0 &&
  4128. (bytesToCopy>=(len=MmGetMdlByteCount (SrcMdl)-SrcOffset))) {
  4129. ASSERT (SrcMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL));
  4130. RtlCopyMemory (dst,
  4131. (PUCHAR)MmGetSystemAddressForMdl(SrcMdl)+SrcOffset,
  4132. len);
  4133. bytesToCopy -= len;
  4134. dst += len;
  4135. SrcMdl = SrcMdl->Next;
  4136. SrcOffset = 0;
  4137. }
  4138. //
  4139. // Copy partial source MDL if space remains
  4140. //
  4141. if (bytesToCopy>0) {
  4142. ASSERT (bytesToCopy<MmGetMdlByteCount (SrcMdl)-SrcOffset);
  4143. ASSERT (SrcMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL));
  4144. RtlCopyMemory (dst,
  4145. (PUCHAR)MmGetSystemAddressForMdl (SrcMdl)+SrcOffset,
  4146. bytesToCopy
  4147. );
  4148. SrcOffset += bytesToCopy;
  4149. }
  4150. //
  4151. // Advance to next MDL in destination
  4152. //
  4153. DstMdl = DstMdl->Next;
  4154. }
  4155. //
  4156. // If we copied everything, return success
  4157. //
  4158. if (SrcLength==0) {
  4159. return STATUS_SUCCESS;
  4160. }
  4161. else {
  4162. //
  4163. // Otherwise, adjust for number of bytes not copied
  4164. // and return destination overflow
  4165. //
  4166. *BytesCopied -= SrcLength;
  4167. return STATUS_BUFFER_OVERFLOW;
  4168. }
  4169. }
  4170. #if DBG
  4171. VOID
  4172. AfdAssert(
  4173. IN PVOID FailedAssertion,
  4174. IN PVOID FileName,
  4175. IN ULONG LineNumber,
  4176. IN PCHAR Message OPTIONAL
  4177. )
  4178. {
  4179. if( AfdUsePrivateAssert ) {
  4180. DbgPrint(
  4181. "\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n",
  4182. Message
  4183. ? Message
  4184. : "",
  4185. FailedAssertion,
  4186. FileName,
  4187. LineNumber
  4188. );
  4189. DbgBreakPoint();
  4190. } else {
  4191. RtlAssert(
  4192. FailedAssertion,
  4193. FileName,
  4194. LineNumber,
  4195. Message
  4196. );
  4197. }
  4198. } // AfdAssert
  4199. #endif // DBG
  4200. NTSTATUS
  4201. FASTCALL
  4202. AfdSetQos(
  4203. IN PIRP Irp,
  4204. IN PIO_STACK_LOCATION IrpSp
  4205. )
  4206. /*++
  4207. Routine Description:
  4208. This routine sets the QOS for the given endpoint. Note that, since
  4209. we don't really (yet) support QOS, we just ignore the incoming
  4210. data and issue a AFD_POLL_QOS or AFD_POLL_GROUP_QOS event as
  4211. appropriate.
  4212. Arguments:
  4213. Irp - Pointer to I/O request packet.
  4214. IrpSp - pointer to the IO stack location to use for this request.
  4215. Return Value:
  4216. NTSTATUS -- Indicates whether the request was successfully queued.
  4217. --*/
  4218. {
  4219. PAFD_ENDPOINT endpoint;
  4220. PAFD_QOS_INFO qosInfo;
  4221. NTSTATUS status = STATUS_SUCCESS;
  4222. #ifdef _WIN64
  4223. if (IoIs32bitProcess (Irp)) {
  4224. status = AfdSetQos32 (Irp, IrpSp);
  4225. goto Complete;
  4226. }
  4227. #endif
  4228. //
  4229. // Set up local pointers.
  4230. //
  4231. endpoint = IrpSp->FileObject->FsContext;
  4232. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4233. qosInfo = Irp->AssociatedIrp.SystemBuffer;
  4234. //
  4235. // Make sure that the input buffer is large enough.
  4236. //
  4237. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  4238. sizeof(*qosInfo) ) {
  4239. status = STATUS_BUFFER_TOO_SMALL;
  4240. goto Complete;
  4241. }
  4242. //
  4243. // If the incoming data doesn't match the default QOS,
  4244. // indicate the appropriate event.
  4245. //
  4246. if( !RtlEqualMemory(
  4247. &qosInfo->Qos,
  4248. &AfdDefaultQos,
  4249. sizeof(QOS)
  4250. ) ) {
  4251. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4252. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  4253. AfdIndicateEventSelectEvent(
  4254. endpoint,
  4255. qosInfo->GroupQos
  4256. ? AFD_POLL_GROUP_QOS
  4257. : AFD_POLL_QOS,
  4258. STATUS_SUCCESS
  4259. );
  4260. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  4261. AfdIndicatePollEvent(
  4262. endpoint,
  4263. qosInfo->GroupQos
  4264. ? AFD_POLL_GROUP_QOS
  4265. : AFD_POLL_QOS,
  4266. STATUS_SUCCESS
  4267. );
  4268. }
  4269. Complete:
  4270. //
  4271. // Complete the IRP.
  4272. //
  4273. Irp->IoStatus.Information = 0;
  4274. Irp->IoStatus.Status = status;
  4275. IoCompleteRequest( Irp, AfdPriorityBoost );
  4276. return status;
  4277. } // AfdSetQos
  4278. NTSTATUS
  4279. FASTCALL
  4280. AfdGetQos(
  4281. IN PIRP Irp,
  4282. IN PIO_STACK_LOCATION IrpSp
  4283. )
  4284. /*++
  4285. Routine Description:
  4286. This routine gets the QOS for the given endpoint.
  4287. Arguments:
  4288. Irp - Pointer to I/O request packet.
  4289. IrpSp - pointer to the IO stack location to use for this request.
  4290. Return Value:
  4291. NTSTATUS -- Indicates whether the request was successfully queued.
  4292. --*/
  4293. {
  4294. PAFD_ENDPOINT endpoint;
  4295. PAFD_QOS_INFO qosInfo;
  4296. NTSTATUS status = STATUS_SUCCESS;
  4297. PAGED_CODE();
  4298. Irp->IoStatus.Information = 0;
  4299. #ifdef _WIN64
  4300. if (IoIs32bitProcess (Irp)) {
  4301. status = AfdGetQos32 (Irp, IrpSp);
  4302. goto Complete;
  4303. }
  4304. #endif
  4305. //
  4306. // Set up local pointers.
  4307. //
  4308. endpoint = IrpSp->FileObject->FsContext;
  4309. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4310. qosInfo = Irp->AssociatedIrp.SystemBuffer;
  4311. //
  4312. // Make sure that the output buffer is large enough.
  4313. //
  4314. if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4315. sizeof(*qosInfo) ) {
  4316. status = STATUS_BUFFER_TOO_SMALL;
  4317. goto Complete;
  4318. }
  4319. //
  4320. // Just return the default data.
  4321. //
  4322. RtlCopyMemory(
  4323. &qosInfo->Qos,
  4324. &AfdDefaultQos,
  4325. sizeof(QOS)
  4326. );
  4327. Irp->IoStatus.Information = sizeof(*qosInfo);
  4328. Complete:
  4329. //
  4330. // Complete the IRP.
  4331. //
  4332. Irp->IoStatus.Status = status;
  4333. IoCompleteRequest( Irp, AfdPriorityBoost );
  4334. return status;
  4335. } // AfdGetQos
  4336. #ifdef _WIN64
  4337. NTSTATUS
  4338. AfdSetQos32(
  4339. IN PIRP Irp,
  4340. IN PIO_STACK_LOCATION IrpSp
  4341. )
  4342. /*++
  4343. Routine Description:
  4344. This routine sets the QOS for the given endpoint. Note that, since
  4345. we don't really (yet) support QOS, we just ignore the incoming
  4346. data and issue a AFD_POLL_QOS or AFD_POLL_GROUP_QOS event as
  4347. appropriate.
  4348. Arguments:
  4349. Irp - Pointer to I/O request packet.
  4350. IrpSp - pointer to the IO stack location to use for this request.
  4351. Return Value:
  4352. NTSTATUS -- Indicates whether the request was successfully queued.
  4353. --*/
  4354. {
  4355. PAFD_ENDPOINT endpoint;
  4356. PAFD_QOS_INFO32 qosInfo;
  4357. //
  4358. // Set up local pointers.
  4359. //
  4360. endpoint = IrpSp->FileObject->FsContext;
  4361. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4362. qosInfo = Irp->AssociatedIrp.SystemBuffer;
  4363. //
  4364. // Make sure that the input buffer is large enough.
  4365. //
  4366. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  4367. sizeof(*qosInfo) ) {
  4368. return STATUS_BUFFER_TOO_SMALL;
  4369. }
  4370. //
  4371. // If the incoming data doesn't match the default QOS,
  4372. // indicate the appropriate event.
  4373. //
  4374. if( !RtlEqualMemory(
  4375. &qosInfo->Qos,
  4376. &AfdDefaultQos32,
  4377. sizeof(QOS32)
  4378. ) ) {
  4379. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4380. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  4381. AfdIndicateEventSelectEvent(
  4382. endpoint,
  4383. qosInfo->GroupQos
  4384. ? AFD_POLL_GROUP_QOS
  4385. : AFD_POLL_QOS,
  4386. STATUS_SUCCESS
  4387. );
  4388. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  4389. AfdIndicatePollEvent(
  4390. endpoint,
  4391. qosInfo->GroupQos
  4392. ? AFD_POLL_GROUP_QOS
  4393. : AFD_POLL_QOS,
  4394. STATUS_SUCCESS
  4395. );
  4396. }
  4397. //
  4398. // Complete the IRP.
  4399. //
  4400. Irp->IoStatus.Information = 0;
  4401. return STATUS_SUCCESS;
  4402. } // AfdSetQos
  4403. NTSTATUS
  4404. AfdGetQos32(
  4405. IN PIRP Irp,
  4406. IN PIO_STACK_LOCATION IrpSp
  4407. )
  4408. /*++
  4409. Routine Description:
  4410. This routine gets the QOS for the given endpoint.
  4411. Arguments:
  4412. Irp - Pointer to I/O request packet.
  4413. IrpSp - pointer to the IO stack location to use for this request.
  4414. Return Value:
  4415. NTSTATUS -- Indicates whether the request was successfully queued.
  4416. --*/
  4417. {
  4418. PAFD_ENDPOINT endpoint;
  4419. PAFD_QOS_INFO32 qosInfo;
  4420. PAGED_CODE();
  4421. //
  4422. // Set up local pointers.
  4423. //
  4424. endpoint = IrpSp->FileObject->FsContext;
  4425. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4426. qosInfo = Irp->AssociatedIrp.SystemBuffer;
  4427. //
  4428. // Make sure that the output buffer is large enough.
  4429. //
  4430. if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4431. sizeof(*qosInfo) ) {
  4432. return STATUS_BUFFER_TOO_SMALL;
  4433. }
  4434. //
  4435. // Just return the default data.
  4436. //
  4437. RtlCopyMemory(
  4438. &qosInfo->Qos,
  4439. &AfdDefaultQos32,
  4440. sizeof(QOS32)
  4441. );
  4442. //
  4443. // Complete the IRP.
  4444. //
  4445. Irp->IoStatus.Information = sizeof(*qosInfo);
  4446. return STATUS_SUCCESS;
  4447. } // AfdGetQos32
  4448. #endif // _WIN64
  4449. NTSTATUS
  4450. AfdValidateStatus (
  4451. NTSTATUS Status
  4452. )
  4453. {
  4454. PAGED_CODE ();
  4455. //
  4456. // Validate the status code.
  4457. // It must match the status code conversion algorithm in msafd.
  4458. //
  4459. switch (Status) {
  4460. case STATUS_SUCCESS:
  4461. // return NO_ERROR;
  4462. case STATUS_INVALID_HANDLE:
  4463. case STATUS_OBJECT_TYPE_MISMATCH:
  4464. // return WSAENOTSOCK;
  4465. case STATUS_INSUFFICIENT_RESOURCES:
  4466. case STATUS_PAGEFILE_QUOTA:
  4467. case STATUS_COMMITMENT_LIMIT:
  4468. case STATUS_WORKING_SET_QUOTA:
  4469. case STATUS_NO_MEMORY:
  4470. case STATUS_CONFLICTING_ADDRESSES:
  4471. case STATUS_QUOTA_EXCEEDED:
  4472. case STATUS_TOO_MANY_PAGING_FILES:
  4473. case STATUS_REMOTE_RESOURCES:
  4474. case STATUS_TOO_MANY_ADDRESSES:
  4475. // return WSAENOBUFS;
  4476. case STATUS_SHARING_VIOLATION:
  4477. case STATUS_ADDRESS_ALREADY_EXISTS:
  4478. // return WSAEADDRINUSE;
  4479. case STATUS_LINK_TIMEOUT:
  4480. case STATUS_IO_TIMEOUT:
  4481. case STATUS_TIMEOUT:
  4482. // return WSAETIMEDOUT;
  4483. case STATUS_GRACEFUL_DISCONNECT:
  4484. // return WSAEDISCON;
  4485. case STATUS_REMOTE_DISCONNECT:
  4486. case STATUS_CONNECTION_RESET:
  4487. case STATUS_LINK_FAILED:
  4488. case STATUS_CONNECTION_DISCONNECTED:
  4489. case STATUS_PORT_UNREACHABLE:
  4490. // return WSAECONNRESET;
  4491. case STATUS_LOCAL_DISCONNECT:
  4492. case STATUS_TRANSACTION_ABORTED:
  4493. case STATUS_CONNECTION_ABORTED:
  4494. // return WSAECONNABORTED;
  4495. case STATUS_BAD_NETWORK_PATH:
  4496. case STATUS_NETWORK_UNREACHABLE:
  4497. case STATUS_PROTOCOL_UNREACHABLE:
  4498. // return WSAENETUNREACH;
  4499. case STATUS_HOST_UNREACHABLE:
  4500. // return WSAEHOSTUNREACH;
  4501. case STATUS_HOST_DOWN:
  4502. // return WSAEHOSTDOWN;
  4503. case STATUS_CANCELLED:
  4504. case STATUS_REQUEST_ABORTED:
  4505. // return WSAEINTR;
  4506. case STATUS_BUFFER_OVERFLOW:
  4507. case STATUS_INVALID_BUFFER_SIZE:
  4508. // return WSAEMSGSIZE;
  4509. case STATUS_BUFFER_TOO_SMALL:
  4510. case STATUS_ACCESS_VIOLATION:
  4511. // return WSAEFAULT;
  4512. // case STATUS_DEVICE_NOT_READY:
  4513. // case STATUS_REQUEST_NOT_ACCEPTED:
  4514. // return WSAEWOULDBLOCK;
  4515. case STATUS_INVALID_NETWORK_RESPONSE:
  4516. case STATUS_NETWORK_BUSY:
  4517. case STATUS_NO_SUCH_DEVICE:
  4518. case STATUS_NO_SUCH_FILE:
  4519. case STATUS_OBJECT_PATH_NOT_FOUND:
  4520. case STATUS_OBJECT_NAME_NOT_FOUND:
  4521. case STATUS_UNEXPECTED_NETWORK_ERROR:
  4522. // return WSAENETDOWN;
  4523. case STATUS_INVALID_CONNECTION:
  4524. // return WSAENOTCONN;
  4525. case STATUS_REMOTE_NOT_LISTENING:
  4526. case STATUS_CONNECTION_REFUSED:
  4527. // return WSAECONNREFUSED;
  4528. case STATUS_PIPE_DISCONNECTED:
  4529. // return WSAESHUTDOWN;
  4530. case STATUS_INVALID_ADDRESS:
  4531. case STATUS_INVALID_ADDRESS_COMPONENT:
  4532. // return WSAEADDRNOTAVAIL;
  4533. case STATUS_NOT_SUPPORTED:
  4534. case STATUS_NOT_IMPLEMENTED:
  4535. // return WSAEOPNOTSUPP;
  4536. case STATUS_ACCESS_DENIED:
  4537. // return WSAEACCES;
  4538. case STATUS_CONNECTION_ACTIVE:
  4539. // return WSAEISCONN;
  4540. break;
  4541. case STATUS_UNSUCCESSFUL:
  4542. case STATUS_INVALID_PARAMETER:
  4543. case STATUS_ADDRESS_CLOSED:
  4544. case STATUS_CONNECTION_INVALID:
  4545. case STATUS_ADDRESS_ALREADY_ASSOCIATED:
  4546. case STATUS_ADDRESS_NOT_ASSOCIATED:
  4547. case STATUS_INVALID_DEVICE_STATE:
  4548. case STATUS_INVALID_DEVICE_REQUEST:
  4549. // return WSAEINVAL;
  4550. break;
  4551. default:
  4552. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  4553. "AfdValidateStatus: Unsupported status code %lx, converting to %lx(INVALID_PARAMETER)\n",
  4554. Status,
  4555. STATUS_INVALID_PARAMETER));
  4556. Status = STATUS_INVALID_PARAMETER;
  4557. break;
  4558. }
  4559. return Status;
  4560. }
  4561. NTSTATUS
  4562. FASTCALL
  4563. AfdNoOperation(
  4564. IN PIRP Irp,
  4565. IN PIO_STACK_LOCATION IrpSp
  4566. )
  4567. /*++
  4568. Routine Description:
  4569. This routine does nothing but complete the IRP.
  4570. Arguments:
  4571. Irp - Pointer to I/O request packet.
  4572. IrpSp - pointer to the IO stack location to use for this request.
  4573. Return Value:
  4574. NTSTATUS -- Indicates whether the request was successfully queued.
  4575. --*/
  4576. {
  4577. PAFD_ENDPOINT endpoint;
  4578. NTSTATUS status;
  4579. PAGED_CODE();
  4580. #ifdef _WIN64
  4581. if (IoIs32bitProcess (Irp)) {
  4582. status = AfdNoOperation32 (Irp, IrpSp);
  4583. goto Complete;
  4584. }
  4585. #endif
  4586. //
  4587. // Set up local pointers.
  4588. //
  4589. endpoint = IrpSp->FileObject->FsContext;
  4590. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4591. //
  4592. // Assume success
  4593. //
  4594. status = STATUS_SUCCESS;
  4595. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength
  4596. >= sizeof (IO_STATUS_BLOCK)) {
  4597. try {
  4598. if (Irp->RequestorMode!=KernelMode) {
  4599. ProbeForRead (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  4600. sizeof (IO_STATUS_BLOCK),
  4601. PROBE_ALIGNMENT(IO_STATUS_BLOCK))
  4602. }
  4603. //
  4604. // Copy the status block
  4605. //
  4606. Irp->IoStatus
  4607. = *((PIO_STATUS_BLOCK)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  4608. Irp->IoStatus.Status = AfdValidateStatus (Irp->IoStatus.Status);
  4609. }
  4610. except (AFD_EXCEPTION_FILTER(&status)) {
  4611. //
  4612. // Fail the call, no completion notification
  4613. // should be delivered via async IO.
  4614. //
  4615. Irp->IoStatus.Status = status;
  4616. Irp->IoStatus.Information = 0;
  4617. }
  4618. }
  4619. else {
  4620. Irp->IoStatus.Status = STATUS_SUCCESS;
  4621. Irp->IoStatus.Information = 0;
  4622. }
  4623. #ifdef _WIN64
  4624. Complete:
  4625. #endif
  4626. if (status==STATUS_SUCCESS && Irp->IoStatus.Status!=STATUS_SUCCESS) {
  4627. //
  4628. // Make sure we deliver error via async IO
  4629. // operation instead of just failing this call itself.
  4630. //
  4631. IoMarkIrpPending (Irp);
  4632. status = STATUS_PENDING;
  4633. }
  4634. else {
  4635. ASSERT (status==Irp->IoStatus.Status);
  4636. }
  4637. IoCompleteRequest( Irp, AfdPriorityBoost );
  4638. return status;
  4639. } // AfdNoOperation
  4640. #ifdef _WIN64
  4641. NTSTATUS
  4642. AfdNoOperation32(
  4643. IN PIRP Irp,
  4644. IN PIO_STACK_LOCATION IrpSp
  4645. )
  4646. /*++
  4647. Routine Description:
  4648. This routine does nothing but complete the IRP.
  4649. Arguments:
  4650. Irp - Pointer to I/O request packet.
  4651. IrpSp - pointer to the IO stack location to use for this request.
  4652. Return Value:
  4653. NTSTATUS -- Indicates whether the request was successfully queued.
  4654. --*/
  4655. {
  4656. PAFD_ENDPOINT endpoint;
  4657. NTSTATUS status;
  4658. PAGED_CODE();
  4659. //
  4660. // Set up local pointers.
  4661. //
  4662. endpoint = IrpSp->FileObject->FsContext;
  4663. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4664. //
  4665. // Assume success
  4666. //
  4667. status = STATUS_SUCCESS;
  4668. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength
  4669. >= sizeof (IO_STATUS_BLOCK32)) {
  4670. try {
  4671. if (Irp->RequestorMode!=KernelMode) {
  4672. ProbeForRead (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  4673. sizeof (IO_STATUS_BLOCK32),
  4674. PROBE_ALIGNMENT32(IO_STATUS_BLOCK32))
  4675. }
  4676. Irp->IoStatus.Status
  4677. = ((PIO_STATUS_BLOCK32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->Status;
  4678. Irp->IoStatus.Information
  4679. = ((PIO_STATUS_BLOCK32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->Information;
  4680. //
  4681. // Validate the status code.
  4682. // It must match the status code conversion algorithm in msafd.
  4683. //
  4684. Irp->IoStatus.Status = AfdValidateStatus (Irp->IoStatus.Status);
  4685. }
  4686. except (AFD_EXCEPTION_FILTER(&status)) {
  4687. //
  4688. // Fail the call, no completion notification
  4689. // should be delivered via async IO.
  4690. //
  4691. Irp->IoStatus.Status = status;
  4692. Irp->IoStatus.Information = 0;
  4693. }
  4694. }
  4695. else {
  4696. Irp->IoStatus.Status = STATUS_SUCCESS;
  4697. Irp->IoStatus.Information = 0;
  4698. }
  4699. return status;
  4700. } // AfdNoOperation32
  4701. #endif //_WIN64
  4702. NTSTATUS
  4703. FASTCALL
  4704. AfdValidateGroup(
  4705. IN PIRP Irp,
  4706. IN PIO_STACK_LOCATION IrpSp
  4707. )
  4708. /*++
  4709. Routine Description:
  4710. This routine examines a group ID. If the ID is for a "constrained"
  4711. group, then all endpoints are scanned to validate the given address
  4712. is consistent with the constrained group.
  4713. Arguments:
  4714. Irp - Pointer to I/O request packet.
  4715. IrpSp - pointer to the IO stack location to use for this request.
  4716. Return Value:
  4717. NTSTATUS -- Indicates whether the request was successfully queued.
  4718. --*/
  4719. {
  4720. PAFD_ENDPOINT endpoint;
  4721. PAFD_ENDPOINT compareEndpoint;
  4722. PAFD_CONNECTION connection;
  4723. PLIST_ENTRY listEntry;
  4724. PAFD_VALIDATE_GROUP_INFO validateInfo;
  4725. AFD_GROUP_TYPE groupType;
  4726. PTRANSPORT_ADDRESS requestAddress;
  4727. ULONG requestAddressLength;
  4728. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4729. BOOLEAN result;
  4730. LONG groupId;
  4731. NTSTATUS status = STATUS_SUCCESS;
  4732. //
  4733. // Set up local pointers.
  4734. //
  4735. endpoint = IrpSp->FileObject->FsContext;
  4736. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  4737. validateInfo = Irp->AssociatedIrp.SystemBuffer;
  4738. //
  4739. // Make sure that the input buffer is large enough.
  4740. //
  4741. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  4742. sizeof(*validateInfo) ) {
  4743. status = STATUS_BUFFER_TOO_SMALL;
  4744. goto Complete;
  4745. }
  4746. if( validateInfo->RemoteAddress.TAAddressCount != 1 ) {
  4747. status = STATUS_INVALID_PARAMETER;
  4748. goto Complete;
  4749. }
  4750. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  4751. ( sizeof(*validateInfo) -
  4752. sizeof(TRANSPORT_ADDRESS) +
  4753. validateInfo->RemoteAddress.Address[0].AddressLength ) ) {
  4754. status = STATUS_BUFFER_TOO_SMALL;
  4755. goto Complete;
  4756. }
  4757. //
  4758. // Start by referencing the group so it doesn't go away unexpectedly.
  4759. // This will also validate the group ID, and give us the group type.
  4760. //
  4761. groupId = validateInfo->GroupID;
  4762. if( !AfdReferenceGroup( groupId, &groupType ) ) {
  4763. status = STATUS_INVALID_PARAMETER;
  4764. goto Complete;
  4765. }
  4766. //
  4767. // If it's not a constrained group ID, we can just complete the IRP
  4768. // successfully right now.
  4769. //
  4770. if( groupType != GroupTypeConstrained ) {
  4771. AfdDereferenceGroup( validateInfo->GroupID );
  4772. Irp->IoStatus.Information = 0;
  4773. status = STATUS_SUCCESS;
  4774. goto Complete;
  4775. }
  4776. //
  4777. // Calculate the size of the incoming TDI address.
  4778. //
  4779. requestAddress = &validateInfo->RemoteAddress;
  4780. requestAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength -
  4781. sizeof(AFD_VALIDATE_GROUP_INFO) +
  4782. sizeof(TRANSPORT_ADDRESS);
  4783. //
  4784. // OK, it's a constrained group. Scan the list of constrained endpoints,
  4785. // find those that are either datagram endpoints or have associated
  4786. // connections, and validate the remote addresses.
  4787. //
  4788. result = TRUE;
  4789. //
  4790. // Make sure the thread in which we execute cannot get
  4791. // suspeneded in APC while we own the global resource.
  4792. //
  4793. KeEnterCriticalRegion ();
  4794. ExAcquireResourceSharedLite( AfdResource, TRUE );
  4795. for( listEntry = AfdConstrainedEndpointListHead.Flink ;
  4796. listEntry != &AfdConstrainedEndpointListHead ;
  4797. listEntry = listEntry->Flink ) {
  4798. compareEndpoint = CONTAINING_RECORD(
  4799. listEntry,
  4800. AFD_ENDPOINT,
  4801. ConstrainedEndpointListEntry
  4802. );
  4803. ASSERT( IS_AFD_ENDPOINT_TYPE( compareEndpoint ) );
  4804. ASSERT( compareEndpoint->GroupType == GroupTypeConstrained );
  4805. //
  4806. // Skip this endpoint if the group IDs don't match.
  4807. //
  4808. if( groupId != compareEndpoint->GroupID ) {
  4809. continue;
  4810. }
  4811. //
  4812. // If this is a datagram endpoint, check it's remote address.
  4813. //
  4814. if( IS_DGRAM_ENDPOINT( compareEndpoint ) ) {
  4815. AfdAcquireSpinLock( &compareEndpoint->SpinLock, &lockHandle );
  4816. if( compareEndpoint->Common.Datagram.RemoteAddress != NULL ) {
  4817. result = AfdCompareAddresses(
  4818. compareEndpoint->Common.Datagram.RemoteAddress,
  4819. compareEndpoint->Common.Datagram.RemoteAddressLength,
  4820. requestAddress,
  4821. requestAddressLength
  4822. );
  4823. }
  4824. AfdReleaseSpinLock( &compareEndpoint->SpinLock, &lockHandle );
  4825. if( !result ) {
  4826. break;
  4827. }
  4828. } else {
  4829. //
  4830. // Not a datagram. If it's a connected endpoint, still has
  4831. // a connection object, and that object has a remote address,
  4832. // then compare the addresses.
  4833. //
  4834. AfdAcquireSpinLock( &compareEndpoint->SpinLock, &lockHandle );
  4835. connection = AFD_CONNECTION_FROM_ENDPOINT( compareEndpoint );
  4836. if( compareEndpoint->State == AfdEndpointStateConnected &&
  4837. connection != NULL ) {
  4838. REFERENCE_CONNECTION( connection );
  4839. if( connection->RemoteAddress != NULL ) {
  4840. result = AfdCompareAddresses(
  4841. connection->RemoteAddress,
  4842. connection->RemoteAddressLength,
  4843. requestAddress,
  4844. requestAddressLength
  4845. );
  4846. }
  4847. AfdReleaseSpinLock( &compareEndpoint->SpinLock, &lockHandle );
  4848. DEREFERENCE_CONNECTION( connection );
  4849. if( !result ) {
  4850. break;
  4851. }
  4852. } else {
  4853. AfdReleaseSpinLock( &compareEndpoint->SpinLock, &lockHandle );
  4854. }
  4855. }
  4856. }
  4857. ExReleaseResourceLite( AfdResource );
  4858. KeLeaveCriticalRegion ();
  4859. AfdDereferenceGroup( validateInfo->GroupID );
  4860. if( !result ) {
  4861. status = STATUS_INVALID_PARAMETER;
  4862. }
  4863. Complete:
  4864. Irp->IoStatus.Information = 0;
  4865. Irp->IoStatus.Status = status;
  4866. IoCompleteRequest( Irp, AfdPriorityBoost );
  4867. return status;
  4868. } // AfdValidateGroup
  4869. BOOLEAN
  4870. AfdCompareAddresses(
  4871. IN PTRANSPORT_ADDRESS Address1,
  4872. IN ULONG Address1Length,
  4873. IN PTRANSPORT_ADDRESS Address2,
  4874. IN ULONG Address2Length
  4875. )
  4876. /*++
  4877. Routine Description:
  4878. This routine compares two addresses in a special way to support
  4879. constrained socket groups. This routine will return TRUE if the
  4880. two addresses represent the same "interface". By "interface", I
  4881. mean something like an IP address or an IPX address. Note that for
  4882. some address types (such as IP) certain portions of the address
  4883. should be ignored (such as the port).
  4884. I really hate hard-coded knowledge of "select" address types, but
  4885. there's no easy way around it. Ideally, this should be the protocol
  4886. driver's responsibility. We could really use a standard "compare
  4887. these addresses" IOCTL in TDI.
  4888. Arguments:
  4889. Address1 - The first address.
  4890. Address1Length - The length of Address1.
  4891. Address2 - The second address.
  4892. Address2Length - The length of Address2.
  4893. Return Value:
  4894. BOOLEAN - TRUE if the addresses reference the same interface, FALSE
  4895. otherwise.
  4896. --*/
  4897. {
  4898. USHORT addressType;
  4899. if (Address1Length!=Address2Length)
  4900. return FALSE;
  4901. if (Address1Length<(ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS,Address[0].Address)) {
  4902. return FALSE;
  4903. }
  4904. addressType = Address1->Address[0].AddressType;
  4905. if( addressType != Address2->Address[0].AddressType ) {
  4906. //
  4907. // If they're not the same address type, they can't be the
  4908. // same address...
  4909. //
  4910. return FALSE;
  4911. }
  4912. //
  4913. // Special case a few addresses.
  4914. //
  4915. switch( addressType ) {
  4916. case TDI_ADDRESS_TYPE_IP : {
  4917. TDI_ADDRESS_IP UNALIGNED * ip1;
  4918. TDI_ADDRESS_IP UNALIGNED * ip2;
  4919. ip1 = (PVOID)&Address1->Address[0].Address[0];
  4920. ip2 = (PVOID)&Address2->Address[0].Address[0];
  4921. //
  4922. // IP addresses. Compare the address portion (ignoring
  4923. // the port).
  4924. //
  4925. if( (Address1Length>=(ULONG)FIELD_OFFSET (TA_IP_ADDRESS, Address[0].Address[0].sin_zero)) &&
  4926. (ip1->in_addr == ip2->in_addr) ) {
  4927. return TRUE;
  4928. }
  4929. }
  4930. return FALSE;
  4931. case TDI_ADDRESS_TYPE_IP6 : {
  4932. TDI_ADDRESS_IP6 UNALIGNED * ip1;
  4933. TDI_ADDRESS_IP6 UNALIGNED * ip2;
  4934. ip1 = (PVOID)&Address1->Address[0].Address;
  4935. ip2 = (PVOID)&Address2->Address[0].Address;
  4936. //
  4937. // IPv6 addresses. Compare the address portion (ignoring
  4938. // the port and flow info).
  4939. //
  4940. if( (Address1Length>=sizeof (TA_IP6_ADDRESS)) &&
  4941. RtlEqualMemory(ip1->sin6_addr,
  4942. ip2->sin6_addr,
  4943. sizeof (ip1->sin6_addr)) ) {
  4944. return TRUE;
  4945. }
  4946. }
  4947. return FALSE;
  4948. case TDI_ADDRESS_TYPE_IPX : {
  4949. TDI_ADDRESS_IPX UNALIGNED * ipx1;
  4950. TDI_ADDRESS_IPX UNALIGNED * ipx2;
  4951. ipx1 = (PVOID)&Address1->Address[0].Address[0];
  4952. ipx2 = (PVOID)&Address2->Address[0].Address[0];
  4953. //
  4954. // IPX addresses. Compare the network and node addresses.
  4955. //
  4956. if( (Address1Length>=sizeof (TA_IPX_ADDRESS)) &&
  4957. ipx1->NetworkAddress == ipx2->NetworkAddress &&
  4958. RtlEqualMemory(
  4959. ipx1->NodeAddress,
  4960. ipx2->NodeAddress,
  4961. sizeof(ipx1->NodeAddress)
  4962. ) ) {
  4963. return TRUE;
  4964. }
  4965. }
  4966. return FALSE;
  4967. case TDI_ADDRESS_TYPE_APPLETALK : {
  4968. TDI_ADDRESS_APPLETALK UNALIGNED * atalk1;
  4969. TDI_ADDRESS_APPLETALK UNALIGNED * atalk2;
  4970. atalk1 = (PVOID)&Address1->Address[0].Address[0];
  4971. atalk2 = (PVOID)&Address2->Address[0].Address[0];
  4972. //
  4973. // APPLETALK address. Compare the network and node
  4974. // addresses.
  4975. //
  4976. if( (Address1Length>=sizeof (TA_APPLETALK_ADDRESS)) &&
  4977. (atalk1->Network == atalk2->Network) &&
  4978. (atalk1->Node == atalk2->Node) ) {
  4979. return TRUE;
  4980. }
  4981. }
  4982. return FALSE;
  4983. case TDI_ADDRESS_TYPE_VNS : {
  4984. TDI_ADDRESS_VNS UNALIGNED * vns1;
  4985. TDI_ADDRESS_VNS UNALIGNED * vns2;
  4986. vns1 = (PVOID)&Address1->Address[0].Address[0];
  4987. vns2 = (PVOID)&Address2->Address[0].Address[0];
  4988. //
  4989. // VNS addresses. Compare the network and subnet addresses.
  4990. //
  4991. if( (Address1Length>=sizeof (TA_VNS_ADDRESS)) &&
  4992. RtlEqualMemory(
  4993. vns1->net_address,
  4994. vns2->net_address,
  4995. sizeof(vns1->net_address)
  4996. ) &&
  4997. RtlEqualMemory(
  4998. vns1->subnet_addr,
  4999. vns2->subnet_addr,
  5000. sizeof(vns1->subnet_addr)
  5001. ) ) {
  5002. return TRUE;
  5003. }
  5004. }
  5005. return FALSE;
  5006. default :
  5007. //
  5008. // Unknown address type. Do a simple memory compare.
  5009. //
  5010. return (BOOLEAN)RtlEqualMemory(
  5011. Address1,
  5012. Address2,
  5013. Address2Length
  5014. );
  5015. }
  5016. } // AfdCompareAddresses
  5017. NTSTATUS
  5018. AfdGetUnacceptedConnectData (
  5019. IN PFILE_OBJECT FileObject,
  5020. IN ULONG IoctlCode,
  5021. IN KPROCESSOR_MODE RequestorMode,
  5022. IN PVOID InputBuffer,
  5023. IN ULONG InputBufferLength,
  5024. IN PVOID OutputBuffer,
  5025. IN ULONG OutputBufferLength,
  5026. OUT PUINT_PTR Information
  5027. )
  5028. {
  5029. PAFD_ENDPOINT endpoint;
  5030. PAFD_CONNECTION connection;
  5031. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  5032. AFD_UNACCEPTED_CONNECT_DATA_INFO connectInfo;
  5033. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5034. ULONG dataLength;
  5035. PMDL mdl;
  5036. NTSTATUS status;
  5037. UCHAR localBuffer[AFD_FAST_CONNECT_DATA_SIZE];
  5038. //
  5039. // Set up local pointers.
  5040. //
  5041. endpoint = FileObject->FsContext;
  5042. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  5043. status = STATUS_SUCCESS;
  5044. mdl = NULL;
  5045. *Information = 0;
  5046. //
  5047. // Validate the request.
  5048. //
  5049. if( !endpoint->Listening ||
  5050. InputBufferLength < sizeof(connectInfo) ) {
  5051. return STATUS_INVALID_PARAMETER;
  5052. }
  5053. try {
  5054. //
  5055. // Validate the input structure if it comes from the user mode
  5056. // application
  5057. //
  5058. if (RequestorMode != KernelMode ) {
  5059. ProbeForRead (InputBuffer,
  5060. sizeof (connectInfo),
  5061. PROBE_ALIGNMENT(AFD_UNACCEPTED_CONNECT_DATA_INFO));
  5062. }
  5063. //
  5064. // Make local copies of the embeded pointer and parameters
  5065. // that we will be using more than once in case malicios
  5066. // application attempts to change them while we are
  5067. // validating
  5068. //
  5069. connectInfo = *((PAFD_UNACCEPTED_CONNECT_DATA_INFO)InputBuffer);
  5070. if (connectInfo.LengthOnly &&
  5071. OutputBufferLength<sizeof (connectInfo)) {
  5072. status = STATUS_INVALID_PARAMETER;
  5073. goto exit;
  5074. }
  5075. if (OutputBufferLength>0) {
  5076. if (OutputBufferLength>sizeof (localBuffer)) {
  5077. mdl = IoAllocateMdl(
  5078. OutputBuffer, // VirtualAddress
  5079. OutputBufferLength, // Length
  5080. FALSE, // SecondaryBuffer
  5081. TRUE, // ChargeQuota
  5082. NULL // Irp
  5083. );
  5084. if (mdl==NULL) {
  5085. status = STATUS_INSUFFICIENT_RESOURCES;
  5086. goto exit;
  5087. }
  5088. MmProbeAndLockPages(
  5089. mdl, // MemoryDescriptorList
  5090. RequestorMode, // AccessMode
  5091. IoWriteAccess // Operation
  5092. );
  5093. OutputBuffer = MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
  5094. if (OutputBuffer==NULL) {
  5095. status = STATUS_INSUFFICIENT_RESOURCES;
  5096. goto exit;
  5097. }
  5098. }
  5099. else {
  5100. if (RequestorMode!=KernelMode) {
  5101. ProbeForWrite (OutputBuffer,
  5102. OutputBufferLength,
  5103. sizeof (UCHAR));
  5104. }
  5105. }
  5106. }
  5107. } except( AFD_EXCEPTION_FILTER(&status) ) {
  5108. goto exit;
  5109. }
  5110. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  5111. //
  5112. // Find the specified connection.
  5113. //
  5114. connection = AfdFindReturnedConnection(
  5115. endpoint,
  5116. connectInfo.Sequence
  5117. );
  5118. if( connection == NULL ) {
  5119. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5120. status = STATUS_INVALID_PARAMETER;
  5121. goto exit;
  5122. }
  5123. //
  5124. // Determine the length of any received connect data.
  5125. //
  5126. dataLength = 0;
  5127. connectDataBuffers = connection->ConnectDataBuffers;
  5128. if( connectDataBuffers != NULL &&
  5129. connectDataBuffers->ReceiveConnectData.Buffer != NULL ) {
  5130. dataLength = connectDataBuffers->ReceiveConnectData.BufferLength;
  5131. }
  5132. //
  5133. // If the caller is just interested in the data length, return it.
  5134. //
  5135. if( connectInfo.LengthOnly ) {
  5136. connectInfo.ConnectDataLength = dataLength;
  5137. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5138. try {
  5139. RtlCopyMemory (OutputBuffer,
  5140. &connectInfo,
  5141. sizeof (connectInfo));
  5142. *Information = sizeof (connectInfo);
  5143. status = STATUS_SUCCESS;
  5144. }
  5145. except (AFD_EXCEPTION_FILTER (&status)) {
  5146. }
  5147. goto exit;
  5148. }
  5149. //
  5150. // If there is no connect data, complete the IRP with no bytes.
  5151. //
  5152. if( dataLength == 0 ) {
  5153. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5154. status = STATUS_SUCCESS;
  5155. goto exit;
  5156. }
  5157. //
  5158. // If the output buffer is too small, fail.
  5159. //
  5160. if( OutputBufferLength < dataLength ) {
  5161. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5162. status = STATUS_BUFFER_TOO_SMALL;
  5163. goto exit;
  5164. }
  5165. RtlCopyMemory(
  5166. mdl ? OutputBuffer : localBuffer,
  5167. connectDataBuffers->ReceiveConnectData.Buffer,
  5168. dataLength
  5169. );
  5170. *Information = dataLength;
  5171. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5172. if (mdl==NULL) {
  5173. try {
  5174. RtlCopyMemory (OutputBuffer,
  5175. localBuffer,
  5176. *Information);
  5177. }
  5178. except (AFD_EXCEPTION_FILTER(&status)) {
  5179. *Information = 0;
  5180. }
  5181. }
  5182. exit:
  5183. if (mdl!=NULL) {
  5184. if (mdl->MdlFlags & MDL_PAGES_LOCKED) {
  5185. MmUnlockPages (mdl);
  5186. }
  5187. IoFreeMdl (mdl);
  5188. }
  5189. return status;
  5190. } // AfdGetUnacceptedConnectData
  5191. #ifdef _WIN64
  5192. ULONG
  5193. AfdComputeCMSGLength32 (
  5194. PVOID ControlBuffer,
  5195. ULONG ControlLength
  5196. )
  5197. {
  5198. ULONG length = 0;
  5199. ASSERT (ControlLength>=sizeof (TDI_CMSGHDR));
  5200. while (ControlLength>=sizeof (TDI_CMSGHDR)) {
  5201. PTDI_CMSGHDR hdr;
  5202. hdr = ControlBuffer;
  5203. //
  5204. // Data comes from the trusted kernel mode driver source.
  5205. //
  5206. ASSERT (ControlLength >= TDI_CMSGHDR_ALIGN((hdr)->cmsg_len));
  5207. ControlLength -= (ULONG)TDI_CMSGHDR_ALIGN((hdr)->cmsg_len);
  5208. ControlBuffer = (PUCHAR)ControlBuffer +
  5209. TDI_CMSGHDR_ALIGN((hdr)->cmsg_len);
  5210. length += (ULONG)TDI_CMSGHDR_ALIGN32(
  5211. (hdr)->cmsg_len -
  5212. TDI_CMSGDATA_ALIGN (sizeof (TDI_CMSGHDR)) +
  5213. TDI_CMSGDATA_ALIGN32(sizeof(TDI_CMSGHDR32)) );
  5214. }
  5215. ASSERT (ControlLength==0);
  5216. return length;
  5217. }
  5218. VOID
  5219. AfdCopyCMSGBuffer32 (
  5220. PVOID Dst,
  5221. PVOID ControlBuffer,
  5222. ULONG CopyLength
  5223. )
  5224. {
  5225. while (CopyLength>=sizeof (TDI_CMSGHDR32)) {
  5226. PTDI_CMSGHDR hdr;
  5227. PTDI_CMSGHDR32 hdr32;
  5228. hdr = ControlBuffer;
  5229. hdr32 = Dst;
  5230. hdr32->cmsg_len = (ULONG)( (hdr)->cmsg_len -
  5231. TDI_CMSGDATA_ALIGN (sizeof (TDI_CMSGHDR)) +
  5232. TDI_CMSGDATA_ALIGN32(sizeof(TDI_CMSGHDR32)) );
  5233. hdr32->cmsg_level = hdr->cmsg_level;
  5234. hdr32->cmsg_type = hdr->cmsg_type;
  5235. if (CopyLength<(ULONG)TDI_CMSGHDR_ALIGN32(hdr32->cmsg_len))
  5236. break;
  5237. CopyLength -= (ULONG)TDI_CMSGHDR_ALIGN32(hdr32->cmsg_len);
  5238. RtlMoveMemory ((PUCHAR)hdr32+TDI_CMSGDATA_ALIGN32(sizeof(TDI_CMSGHDR32)),
  5239. (PUCHAR)hdr+TDI_CMSGDATA_ALIGN(sizeof(TDI_CMSGHDR)),
  5240. hdr32->cmsg_len-TDI_CMSGDATA_ALIGN32(sizeof(TDI_CMSGHDR32)));
  5241. ControlBuffer = (PUCHAR)ControlBuffer +
  5242. TDI_CMSGHDR_ALIGN((hdr)->cmsg_len);
  5243. Dst = (PUCHAR)Dst + TDI_CMSGHDR_ALIGN32((hdr32)->cmsg_len);
  5244. }
  5245. }
  5246. #endif //_WIN64
  5247. //
  5248. // This is currently not used by helper dlls.
  5249. // Commented out because of security concerns
  5250. //
  5251. #if 0
  5252. //
  5253. // Context structure allocated for non-blocking IOCTLs
  5254. //
  5255. typedef struct _AFD_NBIOCTL_CONTEXT {
  5256. AFD_REQUEST_CONTEXT Context; // Context to keep track of request
  5257. ULONG PollEvent; // Poll event to signal upon completion
  5258. // IRP Irp; // Irp to queue transport
  5259. // PCHAR SystemBuffer; // Input buffer if method!=3
  5260. } AFD_NBIOCTL_CONTEXT, *PAFD_NBIOCTL_CONTEXT;
  5261. NTSTATUS
  5262. FASTCALL
  5263. AfdDoTransportIoctl (
  5264. IN PIRP Irp,
  5265. IN PIO_STACK_LOCATION IrpSp
  5266. )
  5267. /*++
  5268. Routine Description:
  5269. Passes the request from the helper DLL to the TDI transport
  5270. driver. In oreder to let the IO system properly complete asynchronous
  5271. IOCTL issued by the helper DLL, it should come on the socket handle
  5272. (afd endpoint object), and then afd redirects it to the transport
  5273. driver on the handle that herlper DLL specifies (normally address,
  5274. connection, or control channel handle)
  5275. Arguments:
  5276. Irp
  5277. IrpSp
  5278. Return Value:
  5279. NTSTATUS
  5280. --*/
  5281. {
  5282. PAFD_ENDPOINT endpoint;
  5283. AFD_TRANSPORT_IOCTL_INFO ioctlInfo;
  5284. PFILE_OBJECT fileObject;
  5285. PDEVICE_OBJECT deviceObject;
  5286. ULONG method;
  5287. PIRP newIrp;
  5288. PIO_STACK_LOCATION nextSp;
  5289. PAFD_REQUEST_CONTEXT requestCtx;
  5290. NTSTATUS status;
  5291. PAGED_CODE ();
  5292. endpoint = IrpSp->FileObject->FsContext;
  5293. ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
  5294. method = IrpSp->Parameters.DeviceIoControl.IoControlCode & 3;
  5295. if (method==METHOD_NEITHER) {
  5296. //
  5297. // We have to manually verify input buffer
  5298. //
  5299. try {
  5300. #ifdef _WIN64
  5301. if (IoIs32bitProcess (Irp)) {
  5302. PAFD_TRANSPORT_IOCTL_INFO32 ioctlInfo32;
  5303. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (*ioctlInfo32)) {
  5304. status = STATUS_INVALID_PARAMETER;
  5305. goto Complete;
  5306. }
  5307. ioctlInfo32 = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  5308. if( Irp->RequestorMode != KernelMode ) {
  5309. ProbeForRead(
  5310. ioctlInfo32,
  5311. sizeof(*ioctlInfo32),
  5312. PROBE_ALIGNEMENT(AFD_TRANSPORT_IOCTL_INFO32)
  5313. );
  5314. }
  5315. ioctlInfo.Handle = ioctlInfo32->Handle;
  5316. ioctlInfo.InputBuffer = ioctlInfo32->InputBuffer;
  5317. ioctlInfo.InputBufferLength = ioctlInfo32->InputBufferLength;
  5318. ioctlInfo.IoControlCode = ioctlInfo32->IoControlCode;
  5319. ioctlInfo.AfdFlags = ioctlInfo32->AfdFlags;
  5320. ioctlInfo.PollEvent = ioctlInfo32->PollEvent;
  5321. }
  5322. else
  5323. #endif // _WIN64
  5324. {
  5325. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (ioctlInfo)) {
  5326. status = STATUS_INVALID_PARAMETER;
  5327. goto Complete;
  5328. }
  5329. if( Irp->RequestorMode != KernelMode ) {
  5330. ProbeForRead(
  5331. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  5332. sizeof(ioctlInfo),
  5333. PROBE_ALIGNMENT(AFD_TRANSPORT_IOCTL_INFO)
  5334. );
  5335. }
  5336. ioctlInfo = *((PAFD_TRANSPORT_IOCTL_INFO)
  5337. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  5338. }
  5339. } except( AFD_EXCEPTION_FILTER(&status) ) {
  5340. //
  5341. // Exception accessing input structure.
  5342. //
  5343. goto Complete;
  5344. }
  5345. }
  5346. else {
  5347. #ifdef _WIN64
  5348. if (IoIs32bitProcess (Irp)) {
  5349. PAFD_TRANSPORT_IOCTL_INFO32 ioctlInfo32;
  5350. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (*ioctlInfo32)) {
  5351. status = STATUS_INVALID_PARAMETER;
  5352. goto Complete;
  5353. }
  5354. ioctlInfo32 = Irp->AssociatedIrp.SystemBuffer;
  5355. ioctlInfo.Handle = ioctlInfo32->Handle;
  5356. ioctlInfo.InputBuffer = ioctlInfo32->InputBuffer;
  5357. ioctlInfo.InputBufferLength = ioctlInfo32->InputBufferLength;
  5358. ioctlInfo.IoControlCode = ioctlInfo32->IoControlCode;
  5359. ioctlInfo.AfdFlags = ioctlInfo32->AfdFlags;
  5360. ioctlInfo.PollEvent = ioctlInfo32->PollEvent;
  5361. }
  5362. else
  5363. #endif // _WIN64
  5364. {
  5365. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (ioctlInfo)) {
  5366. status = STATUS_INVALID_PARAMETER;
  5367. goto Complete;
  5368. }
  5369. //
  5370. // Just copy the buffer verified by the IO system
  5371. //
  5372. ioctlInfo = *((PAFD_TRANSPORT_IOCTL_INFO)
  5373. Irp->AssociatedIrp.SystemBuffer);
  5374. }
  5375. }
  5376. //
  5377. // We rely as much as we can on the IO system to process
  5378. // IOCTL parameters for us. For this we have to make
  5379. // sure that method of AFD and helper DLL IOCTLs
  5380. // are the same, otherwise, someone can play tricks with
  5381. // buffer verification on us.
  5382. //
  5383. // If endpoint is non-blocking and request is not overlapped
  5384. // helper DLL MUST specify an event to check before queueing
  5385. // the request/signal upon its completion
  5386. //
  5387. if ((method!=(ioctlInfo.IoControlCode & 3))
  5388. || (endpoint->NonBlocking
  5389. && !(ioctlInfo.AfdFlags & AFD_OVERLAPPED)
  5390. && !ioctlInfo.PollEvent)
  5391. ) {
  5392. status = STATUS_INVALID_PARAMETER;
  5393. goto Complete;
  5394. }
  5395. //
  5396. // Make sure application has access to handle
  5397. // and get object reference
  5398. //
  5399. status = ObReferenceObjectByHandle(
  5400. ioctlInfo.Handle,
  5401. (ioctlInfo.IoControlCode >> 14) & 3, // DesiredAccess
  5402. *IoFileObjectType, // Must be a file object
  5403. Irp->RequestorMode,
  5404. (PVOID *)&fileObject,
  5405. NULL
  5406. );
  5407. if (NT_SUCCESS(status)) {
  5408. //
  5409. // Get the device object of the driver to which we send the IRP
  5410. //
  5411. deviceObject = IoGetRelatedDeviceObject (fileObject);
  5412. //
  5413. // If this is a non-blocking endpoint and IO is not overlapped
  5414. // and the specified event is not signalled,
  5415. // we'll have complete the helper DLL IRP with
  5416. // STATUS_DEVICE_NOT_READY (translates to WSAEWOUDLBLOCK)
  5417. // and queue another IRP to the transport so that
  5418. // the specified event can be completed when IRP is completed
  5419. //
  5420. if (endpoint->NonBlocking
  5421. && !(ioctlInfo.AfdFlags & AFD_OVERLAPPED)
  5422. && !(ioctlInfo.PollEvent & endpoint->EventsActive)) {
  5423. PAFD_NBIOCTL_CONTEXT nbIoctlCtx;
  5424. USHORT irpSize;
  5425. ULONG allocSize;
  5426. irpSize = IoSizeOfIrp (deviceObject->StackSize);
  5427. //
  5428. // Compute the block size and check for overflow
  5429. //
  5430. allocSize = sizeof (*nbIoctlCtx) + irpSize + ioctlInfo.InputBufferLength;
  5431. if (allocSize < ioctlInfo.InputBufferLength ||
  5432. allocSize < irpSize) {
  5433. status = STATUS_INVALID_PARAMETER;
  5434. ObDereferenceObject (fileObject);
  5435. goto Complete;
  5436. }
  5437. //
  5438. // Allocate an IRP and associated strucutures
  5439. //
  5440. try {
  5441. nbIoctlCtx = AFD_ALLOCATE_POOL_WITH_QUOTA (
  5442. NonPagedPool,
  5443. allocSize,
  5444. AFD_TRANSPORT_IRP_POOL_TAG
  5445. );
  5446. // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
  5447. ASSERT (nbIoctlCtx!=NULL);
  5448. }
  5449. except (EXCEPTION_EXECUTE_HANDLER) {
  5450. status = GetExceptionCode ();
  5451. ObDereferenceObject (fileObject);
  5452. goto Complete;
  5453. }
  5454. //
  5455. // Initialize context structures
  5456. //
  5457. requestCtx = &nbIoctlCtx->Context;
  5458. requestCtx->CleanupRoutine = AfdCleanupNBTransportIoctl;
  5459. nbIoctlCtx->PollEvent = ioctlInfo.PollEvent;
  5460. //
  5461. // Initialize IRP itself
  5462. //
  5463. newIrp = (PIRP)(nbIoctlCtx+1);
  5464. IoInitializeIrp( newIrp, irpSize, deviceObject->StackSize);
  5465. newIrp->RequestorMode = KernelMode;
  5466. newIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
  5467. newIrp->Tail.Overlay.OriginalFileObject = IrpSp->FileObject;
  5468. nextSp = IoGetNextIrpStackLocation (newIrp);
  5469. if ((ioctlInfo.InputBuffer!=NULL)
  5470. && (ioctlInfo.InputBufferLength>0)) {
  5471. //
  5472. // If helper DLL specified input buffer
  5473. // we'll have to make a copy of it in case
  5474. // driver really pends the IRP while we complete the
  5475. // helper DLL IRP an system frees the input buffer
  5476. //
  5477. PVOID newBuffer;
  5478. newBuffer = (PUCHAR)newIrp+IoSizeOfIrp(deviceObject->StackSize);
  5479. try {
  5480. if (Irp->RequestorMode != KernelMode) {
  5481. ProbeForRead(
  5482. ioctlInfo.InputBuffer,
  5483. ioctlInfo.InputBufferLength,
  5484. sizeof(UCHAR)
  5485. );
  5486. }
  5487. RtlCopyMemory (newBuffer,
  5488. ioctlInfo.InputBuffer,
  5489. ioctlInfo.InputBufferLength);
  5490. } except( AFD_EXCEPTION_FILTER(&status) ) {
  5491. //
  5492. // Exception accessing input structure.
  5493. //
  5494. AFD_FREE_POOL (nbIoctlCtx, AFD_TRANSPORT_IRP_POOL_TAG);
  5495. ObDereferenceObject (fileObject);
  5496. goto Complete;
  5497. }
  5498. //
  5499. // Store new buffer parameters in appropriate places
  5500. // in the IRP depending on the method
  5501. //
  5502. if (method==METHOD_NEITHER) {
  5503. nextSp->Parameters.DeviceIoControl.Type3InputBuffer = newBuffer;
  5504. newIrp->AssociatedIrp.SystemBuffer = NULL;
  5505. }
  5506. else {
  5507. nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  5508. newIrp->AssociatedIrp.SystemBuffer = newBuffer;
  5509. }
  5510. nextSp->Parameters.DeviceIoControl.InputBufferLength =
  5511. ioctlInfo.InputBufferLength;
  5512. }
  5513. else {
  5514. //
  5515. // No input buffer, clear correspoinding entries
  5516. //
  5517. nextSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  5518. nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  5519. newIrp->AssociatedIrp.SystemBuffer = NULL;
  5520. }
  5521. //
  5522. // NOTE: We do not allow output buffer parameters on
  5523. // non-blocking calls because the output buffer is deallocated
  5524. // when we complete helper DLL IRP
  5525. //
  5526. // Done during IRP initialization (IoInitializeIrp)
  5527. // newIrp->MdlAddress = NULL;
  5528. // newIrp->UserBuffer = NULL;
  5529. // nextSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  5530. IoSetCompletionRoutine( newIrp, AfdCompleteNBTransportIoctl,
  5531. nbIoctlCtx,
  5532. TRUE, TRUE, TRUE );
  5533. }
  5534. else {
  5535. //
  5536. // Blocking call, reuse the application's IRP
  5537. //
  5538. newIrp = Irp;
  5539. nextSp = IoGetNextIrpStackLocation (Irp);
  5540. nextSp->Parameters.DeviceIoControl.OutputBufferLength =
  5541. IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  5542. if ((ioctlInfo.InputBuffer!=NULL)
  5543. && (ioctlInfo.InputBufferLength>0)) {
  5544. //
  5545. // If application wants to pass input buffer to transport,
  5546. // we'll have to copy it to the system buffer allocated with
  5547. // Irp
  5548. //
  5549. if (method!=METHOD_NEITHER) {
  5550. ULONG sysBufferLength;
  5551. if (method==METHOD_BUFFERED) {
  5552. sysBufferLength = max (
  5553. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  5554. IrpSp->Parameters.DeviceIoControl.OutputBufferLength);
  5555. }
  5556. else {
  5557. sysBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  5558. }
  5559. //
  5560. // Methods 0-2 use system buffer to pass input
  5561. // parameters and we need to reuse original system buffer
  5562. // Make sure it has enough space for this purpose
  5563. //
  5564. try {
  5565. if (Irp->RequestorMode != KernelMode) {
  5566. ProbeForRead(
  5567. ioctlInfo.InputBuffer,
  5568. ioctlInfo.InputBufferLength,
  5569. sizeof(UCHAR)
  5570. );
  5571. }
  5572. if (ioctlInfo.InputBufferLength>sysBufferLength){
  5573. PVOID newSystemBuffer;
  5574. newSystemBuffer = ExAllocatePoolWithQuotaTag (
  5575. NonPagedPoolCacheAligned,
  5576. ioctlInfo.InputBufferLength,
  5577. AFD_TRANSPORT_IRP_POOL_TAG
  5578. );
  5579. if (newSystemBuffer==NULL) {
  5580. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  5581. }
  5582. ExFreePool (Irp->AssociatedIrp.SystemBuffer);
  5583. Irp->AssociatedIrp.SystemBuffer = newSystemBuffer;
  5584. }
  5585. //
  5586. // Copy application data to the system buffer
  5587. //
  5588. RtlCopyMemory (Irp->AssociatedIrp.SystemBuffer,
  5589. ioctlInfo.InputBuffer,
  5590. ioctlInfo.InputBufferLength);
  5591. }
  5592. except( AFD_EXCEPTION_FILTER(&status) ) {
  5593. ObDereferenceObject (fileObject);
  5594. goto Complete;
  5595. }
  5596. nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  5597. }
  5598. else {
  5599. //
  5600. // METHOD_NEITHER, just pass whatever application
  5601. // passed to use, the driver should handle it
  5602. // appropriately.
  5603. //
  5604. // This is of course a potentialy security breach
  5605. // if transport driver is buggy
  5606. //
  5607. nextSp->Parameters.DeviceIoControl.Type3InputBuffer
  5608. = ioctlInfo.InputBuffer;
  5609. }
  5610. nextSp->Parameters.DeviceIoControl.InputBufferLength
  5611. = ioctlInfo.InputBufferLength;
  5612. }
  5613. else {
  5614. //
  5615. // No input buffer, clear correspoiding parameters
  5616. // Note that we can't clean system buffer as
  5617. // it has to be deallocated on completion
  5618. //
  5619. nextSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  5620. nextSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  5621. }
  5622. //
  5623. // We reuse our stack location parameters area for context
  5624. //
  5625. requestCtx = (PAFD_REQUEST_CONTEXT)&IrpSp->Parameters.DeviceIoControl;
  5626. requestCtx->CleanupRoutine = AfdCleanupTransportIoctl;
  5627. IoSetCompletionRoutine( newIrp, AfdCompleteTransportIoctl,
  5628. requestCtx, TRUE, TRUE, TRUE );
  5629. }
  5630. //
  5631. // Set the rest of IRP fields.
  5632. //
  5633. nextSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  5634. nextSp->FileObject = fileObject;
  5635. nextSp->Parameters.DeviceIoControl.IoControlCode = ioctlInfo.IoControlCode;
  5636. //
  5637. // Insert context into the endpoint list so we can cancel
  5638. // the IRP when endpoint is being closed and reference endpoint
  5639. // so it does not go away until this IRP is completed
  5640. //
  5641. requestCtx->Context = newIrp;
  5642. REFERENCE_ENDPOINT (endpoint);
  5643. AfdEnqueueRequest(endpoint,requestCtx);
  5644. //
  5645. // Finally call the transport driver
  5646. //
  5647. status = IoCallDriver (deviceObject, newIrp);
  5648. //
  5649. // We no longer need our private reference to the file object
  5650. // IO system will take care of keeping this reference while our IRP
  5651. // is there
  5652. //
  5653. ObDereferenceObject (fileObject);
  5654. //
  5655. // If we used helper DLL IRP, just return whatever transport
  5656. // driver returned to us
  5657. //
  5658. if (newIrp==Irp)
  5659. return status;
  5660. //
  5661. // If driver pended or immediately completed non-blocking call,
  5662. // make sure helper DLL gets WSAEWOULDBLOCK. It will have to
  5663. // call again whenever the driver completes the IRP and corresponding
  5664. // event is set (if driver completed the IRP, event is set already).
  5665. //
  5666. if (NT_SUCCESS (status))
  5667. status = STATUS_DEVICE_NOT_READY;
  5668. }
  5669. //
  5670. // Complete the application request in case of processing failure or
  5671. // non-blocking call
  5672. //
  5673. Complete:
  5674. Irp->IoStatus.Information = 0;
  5675. Irp->IoStatus.Status = status;
  5676. IoCompleteRequest( Irp, AfdPriorityBoost );
  5677. return status;
  5678. }
  5679. NTSTATUS
  5680. AfdCompleteTransportIoctl (
  5681. IN PDEVICE_OBJECT DeviceObject,
  5682. IN PIRP Irp,
  5683. IN PVOID Context
  5684. )
  5685. /*++
  5686. Routine Description:
  5687. Called to complete transport driver IOCTL for blocking endpoints
  5688. Arguments:
  5689. Return Value:
  5690. STATUS_SUCCESS - IO system should finish IRP processing
  5691. STATUS_MORE_PROCESSING_REQUIRED - we are not yet done (we are actually
  5692. in the middle of cancelling)
  5693. --*/
  5694. {
  5695. PAFD_ENDPOINT endpoint = Irp->Tail.Overlay.OriginalFileObject->FsContext;
  5696. PAFD_REQUEST_CONTEXT requestCtx = Context;
  5697. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5698. NTSTATUS status = STATUS_SUCCESS;
  5699. //
  5700. // We used Parameters structure in our stack location for context
  5701. //
  5702. ASSERT (&(IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl)
  5703. ==Context);
  5704. ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
  5705. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  5706. //
  5707. // We use list entry fields to synchronize with cleanup/cancel
  5708. // routine assuming that as long as the entry is in the list
  5709. // both Flink and Blink fields cannot be NULL. (using these
  5710. // fields for synchronization allows us to cut down on
  5711. // cancel spinlock usage)
  5712. //
  5713. if (AfdIsRequestInQueue(requestCtx)) {
  5714. //
  5715. // Context is still in the list, just remove it so
  5716. // noone can see it anymore
  5717. //
  5718. RemoveEntryList (&requestCtx->EndpointListLink);
  5719. }
  5720. else if (AfdIsRequestCompleted(requestCtx)) {
  5721. //
  5722. // During endpoint cleanup, this context was removed from the
  5723. // list and cancel routine is about to be called, don't let
  5724. // IO system free this IRP until cancel routine is called
  5725. // Also, indicate to the cancel routine that we are done
  5726. // with this IRP and it can complete it.
  5727. //
  5728. AfdMarkRequestCompleted (requestCtx);
  5729. status = STATUS_MORE_PROCESSING_REQUIRED;
  5730. }
  5731. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5732. //
  5733. // Release reference added when we posted this IRP
  5734. //
  5735. DEREFERENCE_ENDPOINT (endpoint);
  5736. return status;
  5737. }
  5738. NTSTATUS
  5739. AfdCompleteNBTransportIoctl (
  5740. IN PDEVICE_OBJECT DeviceObject,
  5741. IN PIRP Irp,
  5742. IN PVOID Context
  5743. )
  5744. /*++
  5745. Routine Description:
  5746. Called to complete transport driver IOCTL for non-blocking endpoints
  5747. Arguments:
  5748. Return Value:
  5749. STATUS_MORE_PROCESSING_REQUIRED - we handle releasing resources
  5750. for this IRP ourselves
  5751. --*/
  5752. {
  5753. PAFD_ENDPOINT endpoint = Irp->Tail.Overlay.OriginalFileObject->FsContext;
  5754. PAFD_NBIOCTL_CONTEXT nbIoctlCtx = Context;
  5755. PAFD_REQUEST_CONTEXT requestCtx = &nbIoctlCtx->Context;
  5756. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5757. //
  5758. // The irp should be a part of our notify structure
  5759. //
  5760. ASSERT (Irp==(PIRP)(nbIoctlCtx+1));
  5761. ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
  5762. //
  5763. // First indicate the event reported by the driver
  5764. //
  5765. ASSERT (nbIoctlCtx->PollEvent!=0);
  5766. AfdIndicatePollEvent (endpoint, 1<<nbIoctlCtx->PollEvent, Irp->IoStatus.Status);
  5767. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  5768. AfdIndicateEventSelectEvent (endpoint, 1<<nbIoctlCtx->PollEvent, Irp->IoStatus.Status);
  5769. //
  5770. // We use list entry fields to synchronize with cleanup/cancel
  5771. // routine assuming that as long as the entry is in the list
  5772. // both Flink and Blink fields cannot be NULL. (using these
  5773. // fields for synchronization allows us to cut down on
  5774. // cancel spinlock usage)
  5775. //
  5776. if (AfdIsRequestInQueue(requestCtx)) {
  5777. //
  5778. // Context is still in the list, just remove it so
  5779. // noone can see it anymore and free the structure
  5780. //
  5781. RemoveEntryList (&requestCtx->EndpointListLink);
  5782. AFD_FREE_POOL (nbIoctlCtx, AFD_TRANSPORT_IRP_POOL_TAG);
  5783. }
  5784. else if (AfdIsRequestCompleted (requestCtx)) {
  5785. //
  5786. // During endpoint cleanup, this context was removed from the
  5787. // list and cancel routine is about to be called, don't
  5788. // free this IRP until cancel routine is called
  5789. // Also, indicate to the cancel routine that we are done
  5790. // with this IRP and it can free it.
  5791. //
  5792. AfdMarkRequestCompleted (requestCtx);
  5793. }
  5794. else {
  5795. //
  5796. // Cancel routine has completed processing this request, free it
  5797. //
  5798. AFD_FREE_POOL (nbIoctlCtx, AFD_TRANSPORT_IRP_POOL_TAG);
  5799. }
  5800. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5801. //
  5802. // Release reference added when we posted this IRP
  5803. //
  5804. DEREFERENCE_ENDPOINT (endpoint);
  5805. return STATUS_MORE_PROCESSING_REQUIRED;
  5806. }
  5807. BOOLEAN
  5808. AfdCleanupTransportIoctl (
  5809. PAFD_ENDPOINT Endpoint,
  5810. PAFD_REQUEST_CONTEXT RequestCtx
  5811. )
  5812. /*++
  5813. Routine Description:
  5814. Cancels outstanding transport IOCTL during endpoint cleanup
  5815. Used for blocking requests.
  5816. Arguments:
  5817. Endpoint - endpoint on which IOCTL was issued
  5818. RequestCtx - context associated with the request
  5819. Return Value:
  5820. TRUE - request has been completed
  5821. FALSE - request is still in driver's queue
  5822. --*/
  5823. {
  5824. PIRP Irp = RequestCtx->Context;
  5825. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5826. //
  5827. // First attempt to cancel the IRP, if it is already completed
  5828. // this is just a no-op. In no case IRP and request structure
  5829. // could have been freed until we mark it as completed as
  5830. // the caller of this routine should have marked the request
  5831. // as being cancelled
  5832. //
  5833. ASSERT (RequestCtx->EndpointListLink.Flink==NULL);
  5834. IoCancelIrp (Irp);
  5835. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  5836. if (AfdIsRequestCompleted (RequestCtx)) {
  5837. //
  5838. // Driver has initiated the completion of the request
  5839. // as we were cancelling it.
  5840. // "Complete the completion"
  5841. //
  5842. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  5843. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  5844. return TRUE;
  5845. }
  5846. else {
  5847. //
  5848. // Driver has not completed the request before returning
  5849. // from cancel routine, mark the request to indicate
  5850. // that we are done with it and completion routine
  5851. // can free it
  5852. //
  5853. AfdMarkRequestCompleted (RequestCtx);
  5854. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  5855. return FALSE;
  5856. }
  5857. }
  5858. BOOLEAN
  5859. AfdCleanupNBTransportIoctl (
  5860. PAFD_ENDPOINT Endpoint,
  5861. PAFD_REQUEST_CONTEXT RequestCtx
  5862. )
  5863. /*++
  5864. Routine Description:
  5865. Cancels outstanding transport IOCTL during endpoint cleanup
  5866. Used for non-blocking requests
  5867. Arguments:
  5868. Endpoint - endpoint on which IOCTL was issued
  5869. RequestCtx - context associated with the request
  5870. Return Value:
  5871. TRUE - request has been completed
  5872. FALSE - request is still in driver's queue
  5873. --*/
  5874. {
  5875. PIRP Irp = RequestCtx->Context;
  5876. AFD_LOCK_QUEUE_HANDLE lockHandle;
  5877. //
  5878. // The IRP should be a part of the context block, verify.
  5879. //
  5880. ASSERT (Irp==(PIRP)(CONTAINING_RECORD (RequestCtx, AFD_NBIOCTL_CONTEXT, Context)+1));
  5881. //
  5882. // First attempt to cancel the IRP, if it is already completed
  5883. // this is just a no-op. In no case IRP and request structure
  5884. // could have been freed until we mark it as completed as
  5885. // the caller of this routine should have marked the request
  5886. // as being cancelled
  5887. //
  5888. ASSERT (RequestCtx->EndpointListLink.Flink==NULL);
  5889. IoCancelIrp (Irp);
  5890. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  5891. if (AfdIsRequestCompleted (RequestCtx)) {
  5892. //
  5893. // Driver has initiated the completion of the request
  5894. // as we were cancelling it.
  5895. // Free the context structure.
  5896. //
  5897. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  5898. AFD_FREE_POOL (
  5899. CONTAINING_RECORD (RequestCtx, AFD_NBIOCTL_CONTEXT, Context),
  5900. AFD_TRANSPORT_IRP_POOL_TAG);
  5901. return TRUE;
  5902. }
  5903. else {
  5904. //
  5905. // Driver has not completed the request before returning
  5906. // from cancel routine, mark the request to indicate
  5907. // that we are done with it and completion routine
  5908. // can free it
  5909. //
  5910. AfdMarkRequestCompleted (RequestCtx);
  5911. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  5912. return FALSE;
  5913. }
  5914. }
  5915. #endif // NOT_YET
  5916. NTSTATUS
  5917. AfdQueryProviderInfo (
  5918. IN PUNICODE_STRING TransportDeviceName,
  5919. OUT PTDI_PROVIDER_INFO ProviderInfo
  5920. )
  5921. /*++
  5922. Routine Description:
  5923. Returns a provider information structure corresponding to the
  5924. specified TDI transport provider.
  5925. Arguments:
  5926. TransportDeviceName - the name of the TDI transport provider.
  5927. ProviderInfo - buffer to place provider info into
  5928. Return Value:
  5929. STATUS_SUCCESS - returned transport info is valid.
  5930. STATUS_OBJECT_NAME_NOT_FOUND - transport's device is not available yet
  5931. --*/
  5932. {
  5933. NTSTATUS status;
  5934. HANDLE controlChannel;
  5935. OBJECT_ATTRIBUTES objectAttributes;
  5936. IO_STATUS_BLOCK iosb;
  5937. TDI_REQUEST_KERNEL_QUERY_INFORMATION kernelQueryInfo;
  5938. PAGED_CODE ();
  5939. //
  5940. // Set up the IRP stack location information to query the TDI
  5941. // provider information.
  5942. //
  5943. kernelQueryInfo.QueryType = TDI_QUERY_PROVIDER_INFORMATION;
  5944. kernelQueryInfo.RequestConnectionInformation = NULL;
  5945. //
  5946. // Open a control channel to the TDI provider.
  5947. // We ask to create a kernel handle which is
  5948. // the handle in the context of the system process
  5949. // so that application cannot close it on us while
  5950. // we are creating and referencing it.
  5951. //
  5952. InitializeObjectAttributes(
  5953. &objectAttributes,
  5954. TransportDeviceName,
  5955. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  5956. NULL,
  5957. NULL
  5958. );
  5959. status = IoCreateFile(
  5960. &controlChannel,
  5961. MAXIMUM_ALLOWED,
  5962. &objectAttributes,
  5963. &iosb, // returned status information.
  5964. 0, // block size (unused).
  5965. 0, // file attributes.
  5966. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5967. FILE_CREATE, // create disposition.
  5968. 0, // create options.
  5969. NULL, // eaInfo
  5970. 0, // eaLength
  5971. CreateFileTypeNone, // CreateFileType
  5972. NULL, // ExtraCreateParameters
  5973. IO_FORCE_ACCESS_CHECK // Options
  5974. | IO_NO_PARAMETER_CHECKING
  5975. );
  5976. if ( NT_SUCCESS(status) ) {
  5977. PFILE_OBJECT controlObject;
  5978. status = ObReferenceObjectByHandle (
  5979. controlChannel, // Handle
  5980. MAXIMUM_ALLOWED, // DesiredAccess
  5981. *IoFileObjectType, // ObjectType
  5982. KernelMode, // AccessMode
  5983. (PVOID *)&controlObject, // Object,
  5984. NULL // HandleInformation
  5985. );
  5986. if (NT_SUCCESS (status)) {
  5987. //
  5988. // Get the TDI provider information for the transport.
  5989. //
  5990. status = AfdIssueDeviceControl(
  5991. controlObject,
  5992. &kernelQueryInfo,
  5993. sizeof(kernelQueryInfo),
  5994. ProviderInfo,
  5995. sizeof(*ProviderInfo),
  5996. TDI_QUERY_INFORMATION
  5997. );
  5998. ObDereferenceObject (controlObject);
  5999. }
  6000. ZwClose( controlChannel );
  6001. }
  6002. if (!NT_SUCCESS (status)) {
  6003. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  6004. "AfdQueryProviderInfo:"
  6005. "Transport %*ls failed provider info query with status %lx.\n",
  6006. TransportDeviceName->Length/2, TransportDeviceName->Buffer, status));
  6007. }
  6008. return status;
  6009. }
  6010. BOOLEAN
  6011. AfdCancelIrp (
  6012. IN PIRP Irp
  6013. )
  6014. /*++
  6015. Routine Description:
  6016. This routine is invoked to cancel an individual I/O Request Packet.
  6017. It is similiar to IoCancelIrp() except that it *must* be called with
  6018. the cancel spin lock held. This routine exists because of the
  6019. synchronization requirements of the cancellation/completion of
  6020. transmit IRPs.
  6021. Arguments:
  6022. Irp - Supplies a pointer to the IRP to be cancelled. The CancelIrql
  6023. field of the IRP must have been correctly initialized with the
  6024. IRQL from the cancel spin lock acquisition.
  6025. Return Value:
  6026. The function value is TRUE if the IRP was in a cancellable state (it
  6027. had a cancel routine), else FALSE is returned.
  6028. Notes:
  6029. It is assumed that the caller has taken the necessary action to ensure
  6030. that the packet cannot be fully completed before invoking this routine.
  6031. --*/
  6032. {
  6033. PDRIVER_CANCEL cancelRoutine;
  6034. //
  6035. // Make sure that the cancel spin lock is held.
  6036. //
  6037. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  6038. //
  6039. // Set the cancel flag in the IRP.
  6040. //
  6041. Irp->Cancel = TRUE;
  6042. //
  6043. // Obtain the address of the cancel routine, and if one was specified,
  6044. // invoke it.
  6045. //
  6046. cancelRoutine = IoSetCancelRoutine( Irp, NULL );
  6047. if (cancelRoutine) {
  6048. if (Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1)) {
  6049. KeBugCheckEx( CANCEL_STATE_IN_COMPLETED_IRP, (ULONG_PTR) Irp, 0, 0, 0 );
  6050. }
  6051. cancelRoutine( Irp->Tail.Overlay.CurrentStackLocation->DeviceObject,
  6052. Irp );
  6053. //
  6054. // The cancel spinlock should have been released by the cancel routine.
  6055. //
  6056. return(TRUE);
  6057. } else {
  6058. //
  6059. // There was no cancel routine, so release the cancel spinlock and
  6060. // return indicating the Irp was not currently cancelable.
  6061. //
  6062. IoReleaseCancelSpinLock( Irp->CancelIrql );
  6063. return(FALSE);
  6064. }
  6065. } // AfdCancelIrp
  6066. VOID
  6067. AfdTrimLookaside (
  6068. PNPAGED_LOOKASIDE_LIST Lookaside
  6069. )
  6070. {
  6071. PVOID entry;
  6072. #if DBG
  6073. LONG count = 0;
  6074. #endif
  6075. while (ExQueryDepthSList (&(Lookaside->L.ListHead))>Lookaside->L.Depth*2) {
  6076. entry = InterlockedPopEntrySList(
  6077. &Lookaside->L.ListHead);
  6078. if (entry) {
  6079. #if DBG
  6080. count++;
  6081. #endif
  6082. (Lookaside->L.Free)(entry);
  6083. }
  6084. else {
  6085. break;
  6086. }
  6087. }
  6088. #if DBG
  6089. if (count>0) {
  6090. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  6091. "AFD: Flushed %d items from lookaside list @ %p\n",
  6092. count, Lookaside));
  6093. }
  6094. #endif
  6095. }
  6096. VOID
  6097. AfdCheckLookasideLists (
  6098. IN PKDPC Dpc,
  6099. IN PVOID DeferredContext,
  6100. IN PVOID SystemArgument1,
  6101. IN PVOID SystemArgument2
  6102. )
  6103. {
  6104. LONG i;
  6105. ASSERT (Dpc==&AfdLookasideLists->Dpc);
  6106. ASSERT (DeferredContext==AfdLookasideLists);
  6107. for (i=0; i<AFD_NUM_LOOKASIDE_LISTS; i++) {
  6108. if (ExQueryDepthSList (&(AfdLookasideLists->List[i].L.ListHead)) >
  6109. AfdLookasideLists->List[i].L.Depth*2) {
  6110. if (AfdLookasideLists->TrimFlags & (1<<i)) {
  6111. AfdTrimLookaside (&AfdLookasideLists->List[i]);
  6112. AfdLookasideLists->TrimFlags &= (~(1<<i));
  6113. }
  6114. else {
  6115. AfdLookasideLists->TrimFlags |= (1<<i);
  6116. }
  6117. }
  6118. else if (AfdLookasideLists->TrimFlags & (1<<i)) {
  6119. AfdLookasideLists->TrimFlags &= (~(1<<i));
  6120. }
  6121. }
  6122. }
  6123. VOID
  6124. AfdLRListAddItem (
  6125. PAFD_LR_LIST_ITEM Item,
  6126. PAFD_LR_LIST_ROUTINE Routine
  6127. )
  6128. /*++
  6129. Adds item to low resource list and starts low resource timer if not already
  6130. started.
  6131. Arguments:
  6132. Item - item to add
  6133. Routine - routine to execute when timeout expires.
  6134. Return Value:
  6135. None
  6136. Notes:
  6137. --*/
  6138. {
  6139. LONG count;
  6140. Item->Routine = Routine;
  6141. InterlockedPushEntrySList (
  6142. &AfdLRList,
  6143. &Item->SListLink);
  6144. count = InterlockedIncrement (&AfdLRListCount);
  6145. ASSERT (count>0);
  6146. if (count==1) {
  6147. AfdLRStartTimer ();
  6148. }
  6149. }
  6150. VOID
  6151. AfdLRListTimeout (
  6152. IN PKDPC Dpc,
  6153. IN PVOID DeferredContext,
  6154. IN PVOID SystemArgument1,
  6155. IN PVOID SystemArgument2
  6156. )
  6157. /*++
  6158. DPC routine for low resource list timer
  6159. Simply schedules worker thread - do not want to do low resource processing at DPC
  6160. --*/
  6161. {
  6162. AfdQueueWorkItem (AfdProcessLRList, &AfdLRListWorker);
  6163. }
  6164. VOID
  6165. AfdProcessLRList (
  6166. PVOID Param
  6167. )
  6168. /*++
  6169. Routine Description:
  6170. Processeses items on low resource list and reschedules processing
  6171. if unprocessed items remain (still failing to buffer data due to
  6172. low resource condition)
  6173. Arguments:
  6174. None
  6175. Return Value:
  6176. None
  6177. Notes:
  6178. --*/
  6179. {
  6180. PSINGLE_LIST_ENTRY localList, entry;
  6181. LONG count = 0;
  6182. PAGED_CODE ();
  6183. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  6184. "AFD: Processing low resource list: %ld entries\n",
  6185. AfdLRListCount));
  6186. //
  6187. // Flush the list
  6188. //
  6189. localList = InterlockedFlushSList (&AfdLRList);
  6190. //
  6191. // Reverse it to preserve order of processing (FIFO).
  6192. //
  6193. entry = NULL;
  6194. while (localList!=NULL) {
  6195. PSINGLE_LIST_ENTRY next;
  6196. next = localList->Next;
  6197. localList->Next = entry;
  6198. entry = localList;
  6199. localList = next;
  6200. }
  6201. localList = entry;
  6202. while (localList!=NULL) {
  6203. PAFD_LR_LIST_ITEM item;
  6204. entry = localList;
  6205. localList = localList->Next;
  6206. item = CONTAINING_RECORD (entry, AFD_LR_LIST_ITEM, SListLink);
  6207. //
  6208. // Try to restart receive processing on connection where buffer allocation failed
  6209. //
  6210. if (item->Routine (item)) {
  6211. //
  6212. // Success, decrement number of items outstanding,
  6213. // and note current number of items. If we did not empty
  6214. // the list, we'll have to restart the timer.
  6215. //
  6216. count = InterlockedDecrement (&AfdLRListCount);
  6217. ASSERT (count>=0);
  6218. }
  6219. else {
  6220. //
  6221. // Failure, put it back on the list. Note, that we have at list one
  6222. // item there and thus have to restart the timer again.
  6223. //
  6224. InterlockedPushEntrySList (&AfdLRList, &item->SListLink);
  6225. count = 1;
  6226. }
  6227. }
  6228. if (count!=0) {
  6229. //
  6230. // We did not empty the list, so restart the timer.
  6231. //
  6232. AfdLRStartTimer ();
  6233. }
  6234. }
  6235. VOID
  6236. AfdLRStartTimer (
  6237. VOID
  6238. )
  6239. /*++
  6240. Routine Description:
  6241. Start low resource timer to retry receive operation on connections
  6242. that could not buffer data due to low reaource condition.
  6243. Arguments:
  6244. None
  6245. Return Value:
  6246. None
  6247. Notes:
  6248. --*/
  6249. {
  6250. LARGE_INTEGER timeout;
  6251. BOOLEAN res;
  6252. timeout.QuadPart = -50000000i64; // 5 seconds
  6253. #if DBG
  6254. {
  6255. TIME_FIELDS timeFields;
  6256. LARGE_INTEGER currentTime;
  6257. LARGE_INTEGER localTime;
  6258. KeQuerySystemTime (&currentTime);
  6259. currentTime.QuadPart -= timeout.QuadPart;
  6260. ExSystemTimeToLocalTime (&currentTime, &localTime);
  6261. RtlTimeToTimeFields (&localTime, &timeFields);
  6262. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  6263. "AFD: Scheduling low resource timer for %2.2d:%2.2d:%2.2d\n",
  6264. timeFields.Hour,
  6265. timeFields.Minute,
  6266. timeFields.Second));
  6267. }
  6268. #endif
  6269. KeInitializeDpc(
  6270. &AfdLRListDpc,
  6271. AfdLRListTimeout,
  6272. &AfdLRList
  6273. );
  6274. KeInitializeTimer( &AfdLRListTimer );
  6275. res = KeSetTimer(
  6276. &AfdLRListTimer,
  6277. timeout,
  6278. &AfdLRListDpc
  6279. );
  6280. ASSERT (res==FALSE);
  6281. }
  6282. #ifdef _AFD_VERIFY_DATA_
  6283. VOID
  6284. AfdVerifyBuffer (
  6285. PAFD_CONNECTION Connection,
  6286. PVOID Buffer,
  6287. ULONG Length
  6288. )
  6289. {
  6290. if (Connection->VerifySequenceNumber!=0) {
  6291. PUCHAR start, end;
  6292. ULONGLONG seq;
  6293. for (start=Buffer,
  6294. end = (PUCHAR)Buffer+Length,
  6295. seq = Connection->VerifySequenceNumber-1;
  6296. start<end;
  6297. seq++, start++) {
  6298. ULONG num = (ULONG)(seq/4);
  6299. ULONG byte = (ULONG)(seq%4);
  6300. if (*start!=(UCHAR)(num>>(byte*8))) {
  6301. DbgPrint ("AfdVerifyBuffer: Data sequence number mismatch on connection %p:\n"
  6302. " data buffer-%p, offset-%lx, expected-%2.2lx, got-%2.2lx.\n",
  6303. Connection,
  6304. Buffer,
  6305. start-(PUCHAR)Buffer,
  6306. (UCHAR)(num>>(byte*8)),
  6307. *start);
  6308. DbgBreakPoint ();
  6309. //
  6310. // Disable verification to continue.
  6311. //
  6312. Connection->VerifySequenceNumber = 0;
  6313. return;
  6314. }
  6315. }
  6316. Connection->VerifySequenceNumber = seq+1;
  6317. }
  6318. }
  6319. VOID
  6320. AfdVerifyMdl (
  6321. PAFD_CONNECTION Connection,
  6322. PMDL Mdl,
  6323. ULONG Offset,
  6324. ULONG Length
  6325. ) {
  6326. if (Connection->VerifySequenceNumber!=0) {
  6327. while (Mdl!=NULL) {
  6328. if (Offset>=MmGetMdlByteCount (Mdl)) {
  6329. Offset-=MmGetMdlByteCount (Mdl);
  6330. }
  6331. else if (Length<=MmGetMdlByteCount (Mdl)-Offset) {
  6332. AfdVerifyBuffer (Connection,
  6333. (PUCHAR)MmGetSystemAddressForMdl (Mdl)+Offset,
  6334. Length);
  6335. break;
  6336. }
  6337. else {
  6338. AfdVerifyBuffer (Connection,
  6339. (PUCHAR)MmGetSystemAddressForMdl (Mdl)+Offset,
  6340. MmGetMdlByteCount (Mdl)-Offset
  6341. );
  6342. Length-=(MmGetMdlByteCount (Mdl)-Offset);
  6343. Offset = 0;
  6344. }
  6345. Mdl = Mdl->Next;
  6346. }
  6347. }
  6348. }
  6349. ULONG AfdVerifyType = 0;
  6350. ULONG AfdVerifyPort = 0;
  6351. PEPROCESS AfdVerifyProcess = NULL;
  6352. VOID
  6353. AfdVerifyAddress (
  6354. PAFD_CONNECTION Connection,
  6355. PTRANSPORT_ADDRESS Address
  6356. )
  6357. {
  6358. Connection->VerifySequenceNumber = 0;
  6359. if ((AfdVerifyPort==0) ||
  6360. ((AfdVerifyProcess!=NULL) &&
  6361. (AfdVerifyProcess!=Connection->OwningProcess)) ||
  6362. ((AfdVerifyType!=0) &&
  6363. (AfdVerifyType!=(USHORT)Address->Address[0].AddressType))
  6364. ) {
  6365. return;
  6366. }
  6367. switch (Address->Address[0].AddressType) {
  6368. case TDI_ADDRESS_TYPE_IP : {
  6369. TDI_ADDRESS_IP UNALIGNED * ip;
  6370. ip = (PVOID)&Address->Address[0].Address[0];
  6371. if (ip->sin_port!=(USHORT)AfdVerifyPort) {
  6372. return;
  6373. }
  6374. }
  6375. break;
  6376. case TDI_ADDRESS_TYPE_IPX : {
  6377. TDI_ADDRESS_IPX UNALIGNED * ipx;
  6378. ipx = (PVOID)&Address->Address[0].Address[0];
  6379. if (ipx->Socket!=(USHORT)AfdVerifyPort) {
  6380. return;
  6381. }
  6382. }
  6383. break;
  6384. case TDI_ADDRESS_TYPE_APPLETALK : {
  6385. TDI_ADDRESS_APPLETALK UNALIGNED * atalk;
  6386. atalk = (PVOID)&Address->Address[0].Address[0];
  6387. if (atalk->Socket!=(UCHAR)AfdVerifyPort) {
  6388. return;
  6389. }
  6390. }
  6391. break;
  6392. default:
  6393. if (AfdVerifyType==0)
  6394. return;
  6395. DbgPrint ("AfdVerifyAddress: connection-%8.8lx, addres-%8.8lx\n",
  6396. Connection, Address);
  6397. DbgBreakPoint ();
  6398. }
  6399. Connection->VerifySequenceNumber = 1;
  6400. }
  6401. #endif // _AFD_VERIFY_DATA_
  6402. LONG
  6403. AfdExceptionFilter(
  6404. #if DBG
  6405. PCHAR SourceFile,
  6406. LONG LineNumber,
  6407. #endif
  6408. PEXCEPTION_POINTERS ExceptionPointers,
  6409. PNTSTATUS ExceptionCode
  6410. )
  6411. {
  6412. PAGED_CODE ();
  6413. //
  6414. // Return exception code and translate alignment warnings into
  6415. // alignment errors if requested.
  6416. //
  6417. if (ExceptionCode) {
  6418. *ExceptionCode = ExceptionPointers->ExceptionRecord->ExceptionCode;
  6419. if (*ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) {
  6420. *ExceptionCode = STATUS_DATATYPE_MISALIGNMENT_ERROR;
  6421. }
  6422. }
  6423. #if DBG
  6424. //
  6425. // Protect ourselves in case the process is totally messed up.
  6426. //
  6427. try {
  6428. PCHAR fileName;
  6429. //
  6430. // Strip off the path from the source file.
  6431. //
  6432. fileName = strrchr( SourceFile, '\\' );
  6433. if( fileName == NULL ) {
  6434. fileName = SourceFile;
  6435. } else {
  6436. fileName++;
  6437. }
  6438. //
  6439. // Whine about the exception.
  6440. //
  6441. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
  6442. "AfdExceptionFilter: exception %08lx @ %08lx, caught in %s:%d\n",
  6443. ExceptionPointers->ExceptionRecord->ExceptionCode,
  6444. ExceptionPointers->ExceptionRecord->ExceptionAddress,
  6445. fileName,
  6446. LineNumber
  6447. ));
  6448. }
  6449. except( EXCEPTION_EXECUTE_HANDLER ) {
  6450. //
  6451. // Not much we can do here...
  6452. //
  6453. NOTHING;
  6454. }
  6455. #endif //DBG
  6456. return EXCEPTION_EXECUTE_HANDLER;
  6457. } // AfdExceptionFilter
  6458. #if DBG
  6459. LONG
  6460. AfdApcExceptionFilter(
  6461. PEXCEPTION_POINTERS ExceptionPointers,
  6462. PCHAR SourceFile,
  6463. LONG LineNumber
  6464. )
  6465. {
  6466. PCHAR fileName;
  6467. PAGED_CODE ();
  6468. //
  6469. // Protect ourselves in case the process is totally messed up.
  6470. //
  6471. try {
  6472. //
  6473. // Strip off the path from the source file.
  6474. //
  6475. fileName = strrchr( SourceFile, '\\' );
  6476. if( fileName == NULL ) {
  6477. fileName = SourceFile;
  6478. } else {
  6479. fileName++;
  6480. }
  6481. //
  6482. // Whine about the exception.
  6483. //
  6484. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL,
  6485. "AfdApcExceptionFilter: exception %08lx, exr:%p cxr:%p, caught in %s:%d\n",
  6486. ExceptionPointers->ExceptionRecord->ExceptionCode,
  6487. ExceptionPointers->ExceptionRecord,
  6488. ExceptionPointers->ContextRecord,
  6489. fileName,
  6490. LineNumber
  6491. ));
  6492. DbgBreakPoint ();
  6493. }
  6494. except( EXCEPTION_EXECUTE_HANDLER ) {
  6495. //
  6496. // Not much we can do here...
  6497. //
  6498. NOTHING;
  6499. }
  6500. return EXCEPTION_CONTINUE_SEARCH;
  6501. } // AfdApcExceptionFilter
  6502. #endif