Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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