Windows NT 4.0 source code leak
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.

4804 lines
108 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 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. --*/
  11. #include "afdp.h"
  12. #define TL_INSTANCE 0
  13. #include <ipexport.h>
  14. #include <tdiinfo.h>
  15. #include <tcpinfo.h>
  16. #include <ntddtcp.h>
  17. VOID
  18. AfdDoWork (
  19. IN PVOID Context
  20. );
  21. NTSTATUS
  22. AfdRestartDeviceControl (
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp,
  25. IN PVOID Context
  26. );
  27. VOID
  28. AfdUnlockDriver (
  29. IN PVOID Context
  30. );
  31. #ifdef NT351
  32. typedef struct _AFD_APC {
  33. KAPC Apc;
  34. } AFD_APC, *PAFD_APC;
  35. VOID
  36. AfdSpecialApc (
  37. struct _KAPC *Apc,
  38. PKNORMAL_ROUTINE *NormalRoutine,
  39. PVOID *NormalContext,
  40. PVOID *SystemArgument1,
  41. PVOID *SystemArgument2
  42. );
  43. VOID
  44. AfdSpecialApcRundown (
  45. struct _KAPC *Apc
  46. );
  47. #endif // NT351
  48. BOOLEAN
  49. AfdCompareAddresses(
  50. IN PTRANSPORT_ADDRESS Address1,
  51. IN ULONG Address1Length,
  52. IN PTRANSPORT_ADDRESS Address2,
  53. IN ULONG Address2Length
  54. );
  55. PAFD_CONNECTION
  56. AfdFindReturnedConnection(
  57. IN PAFD_ENDPOINT Endpoint,
  58. IN ULONG Sequence
  59. );
  60. #ifdef ALLOC_PRAGMA
  61. #pragma alloc_text( PAGE, AfdCalcBufferArrayByteLengthRead )
  62. #pragma alloc_text( PAGE, AfdCalcBufferArrayByteLengthWrite )
  63. #pragma alloc_text( PAGE, AfdCopyBufferArrayToBuffer )
  64. #pragma alloc_text( PAGE, AfdCopyBufferToBufferArray )
  65. #pragma alloc_text( PAGEAFD, AfdAdvanceMdlChain )
  66. #pragma alloc_text( PAGEAFD, AfdAllocateMdlChain )
  67. #pragma alloc_text( PAGE, AfdQueryHandles )
  68. #pragma alloc_text( PAGE, AfdGetInformation )
  69. #pragma alloc_text( PAGE, AfdSetInformation )
  70. #pragma alloc_text( PAGE, AfdSetInLineMode )
  71. #pragma alloc_text( PAGE, AfdGetContext )
  72. #pragma alloc_text( PAGE, AfdGetContextLength )
  73. #pragma alloc_text( PAGE, AfdSetContext )
  74. #pragma alloc_text( PAGE, AfdIssueDeviceControl )
  75. #pragma alloc_text( PAGE, AfdSetEventHandler )
  76. #pragma alloc_text( PAGE, AfdInsertNewEndpointInList )
  77. #pragma alloc_text( PAGE, AfdRemoveEndpointFromList )
  78. #pragma alloc_text( PAGEAFD, AfdCompleteIrpList )
  79. #pragma alloc_text( PAGEAFD, AfdErrorEventHandler )
  80. //#pragma alloc_text( PAGEAFD, AfdRestartDeviceControl ) // can't ever be paged!
  81. #pragma alloc_text( PAGEAFD, AfdGetConnectData )
  82. #pragma alloc_text( PAGEAFD, AfdSetConnectData )
  83. #pragma alloc_text( PAGEAFD, AfdFreeConnectDataBuffers )
  84. #pragma alloc_text( PAGEAFD, AfdSaveReceivedConnectData )
  85. //#pragma alloc_text( PAGEAFD, AfdDoWork )
  86. #pragma alloc_text( PAGEAFD, AfdAllocateWorkItem )
  87. #pragma alloc_text( PAGEAFD, AfdQueueWorkItem )
  88. #pragma alloc_text( PAGEAFD, AfdFreeWorkItem )
  89. #if DBG
  90. #pragma alloc_text( PAGEAFD, AfdIoCallDriverDebug )
  91. #pragma alloc_text( PAGEAFD, AfdAllocateWorkItemPool )
  92. #pragma alloc_text( PAGEAFD, AfdFreeWorkItemPool )
  93. #else
  94. #pragma alloc_text( PAGEAFD, AfdIoCallDriverFree )
  95. #endif
  96. #ifdef NT351
  97. #pragma alloc_text( PAGE, AfdReferenceEventObjectByHandle )
  98. #pragma alloc_text( PAGE, AfdQueueUserApc )
  99. #pragma alloc_text( PAGE, AfdSpecialApc )
  100. #pragma alloc_text( PAGE, AfdSpecialApcRundown )
  101. #endif
  102. #pragma alloc_text( PAGE, AfdSetQos )
  103. #pragma alloc_text( PAGE, AfdGetQos )
  104. #pragma alloc_text( PAGE, AfdNoOperation )
  105. #pragma alloc_text( PAGE, AfdValidateGroup )
  106. #pragma alloc_text( PAGE, AfdCompareAddresses )
  107. #pragma alloc_text( PAGE, AfdGetUnacceptedConnectData )
  108. #pragma alloc_text( PAGE, AfdFindReturnedConnection )
  109. #endif
  110. VOID
  111. AfdCompleteIrpList (
  112. IN PLIST_ENTRY IrpListHead,
  113. IN PKSPIN_LOCK SpinLock,
  114. IN NTSTATUS Status,
  115. IN PAFD_IRP_CLEANUP_ROUTINE CleanupRoutine OPTIONAL
  116. )
  117. /*++
  118. Routine Description:
  119. Completes a list of IRPs with the specified status.
  120. Arguments:
  121. IrpListHead - the head of the list of IRPs to complete.
  122. SpinLock - a lock which protects the list of IRPs.
  123. Status - the status to use for completing the IRPs.
  124. CleanupRoutine - a pointer to an optional IRP cleanup routine called
  125. before the IRP is completed.
  126. Return Value:
  127. None.
  128. --*/
  129. {
  130. PLIST_ENTRY listEntry;
  131. PIRP irp;
  132. KIRQL oldIrql;
  133. KIRQL cancelIrql;
  134. IoAcquireCancelSpinLock( &cancelIrql );
  135. AfdAcquireSpinLock( SpinLock, &oldIrql );
  136. while ( !IsListEmpty( IrpListHead ) ) {
  137. //
  138. // Remove the first IRP from the list, get a pointer to
  139. // the IRP and reset the cancel routine in the IRP. The
  140. // IRP is no longer cancellable.
  141. //
  142. listEntry = RemoveHeadList( IrpListHead );
  143. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  144. IoSetCancelRoutine( irp, NULL );
  145. //
  146. // If we have a cleanup routine, call it.
  147. //
  148. if( CleanupRoutine != NULL ) {
  149. (CleanupRoutine)( irp );
  150. }
  151. //
  152. // We must release the locks in order to actually
  153. // complete the IRP. It is OK to release these locks
  154. // because we don't maintain any absolute pointer into
  155. // the list; the loop termination condition is just
  156. // whether the list is completely empty.
  157. //
  158. AfdReleaseSpinLock( SpinLock, oldIrql );
  159. IoReleaseCancelSpinLock( cancelIrql );
  160. //
  161. // Complete the IRP.
  162. //
  163. irp->IoStatus.Status = Status;
  164. irp->IoStatus.Information = 0;
  165. IoCompleteRequest( irp, AfdPriorityBoost );
  166. //
  167. // Reacquire the locks and continue completing IRPs.
  168. //
  169. IoAcquireCancelSpinLock( &cancelIrql );
  170. AfdAcquireSpinLock( SpinLock, &oldIrql );
  171. }
  172. AfdReleaseSpinLock( SpinLock, oldIrql );
  173. IoReleaseCancelSpinLock( cancelIrql );
  174. return;
  175. } // AfdCompleteIrpList
  176. NTSTATUS
  177. AfdErrorEventHandler (
  178. IN PVOID TdiEventContext,
  179. IN NTSTATUS Status
  180. )
  181. {
  182. IF_DEBUG(CONNECT) {
  183. KdPrint(( "AfdErrorEventHandler called for endpoint %lx\n",
  184. TdiEventContext ));
  185. }
  186. return STATUS_SUCCESS;
  187. } // AfdErrorEventHandler
  188. VOID
  189. AfdInsertNewEndpointInList (
  190. IN PAFD_ENDPOINT Endpoint
  191. )
  192. /*++
  193. Routine Description:
  194. Inserts a new endpoint in the global list of AFD endpoints. If this
  195. is the first endpoint, then this routine does various allocations to
  196. prepare AFD for usage.
  197. Arguments:
  198. Endpoint - the endpoint being added.
  199. Return Value:
  200. None.
  201. --*/
  202. {
  203. PAGED_CODE( );
  204. //
  205. // Acquire a lock which prevents other threads from performing this
  206. // operation.
  207. //
  208. ExAcquireResourceExclusive( AfdResource, TRUE );
  209. InterlockedIncrement(
  210. &AfdEndpointsOpened
  211. );
  212. //
  213. // If the list of endpoints is empty, do some allocations.
  214. //
  215. if ( IsListEmpty( &AfdEndpointListHead ) ) {
  216. //
  217. // Tell MM to revert to normal paging semantics.
  218. //
  219. MmResetDriverPaging( DriverEntry );
  220. //
  221. // Lock down the AFD section that cannot be pagable if any
  222. // sockets are open.
  223. //
  224. ASSERT( AfdDiscardableCodeHandle == NULL );
  225. AfdDiscardableCodeHandle = MmLockPagableCodeSection( AfdGetBuffer );
  226. ASSERT( AfdDiscardableCodeHandle != NULL );
  227. AfdLoaded = TRUE;
  228. }
  229. //
  230. // Add the endpoint to the list(s).
  231. //
  232. ExInterlockedInsertHeadList(
  233. &AfdEndpointListHead,
  234. &Endpoint->GlobalEndpointListEntry,
  235. &AfdSpinLock
  236. );
  237. if( Endpoint->GroupType == GroupTypeConstrained ) {
  238. ExInterlockedInsertHeadList(
  239. &AfdConstrainedEndpointListHead,
  240. &Endpoint->ConstrainedEndpointListEntry,
  241. &AfdSpinLock
  242. );
  243. }
  244. //
  245. // Release the lock and return.
  246. //
  247. ExReleaseResource( AfdResource );
  248. return;
  249. } // AfdInsertNewEndpointInList
  250. VOID
  251. AfdRemoveEndpointFromList (
  252. IN PAFD_ENDPOINT Endpoint
  253. )
  254. /*++
  255. Routine Description:
  256. Removes a new endpoint from the global list of AFD endpoints. If
  257. this is the last endpoint in the list, then this routine does
  258. various deallocations to save resource utilization.
  259. Arguments:
  260. Endpoint - the endpoint being removed.
  261. Return Value:
  262. None.
  263. --*/
  264. {
  265. PAGED_CODE( );
  266. //
  267. // Acquire a lock which prevents other threads from performing this
  268. // operation.
  269. //
  270. ExAcquireResourceExclusive( AfdResource, TRUE );
  271. InterlockedIncrement(
  272. &AfdEndpointsClosed
  273. );
  274. //
  275. // Remove the endpoint from the list(s).
  276. //
  277. AfdInterlockedRemoveEntryList(
  278. &Endpoint->GlobalEndpointListEntry,
  279. &AfdSpinLock
  280. );
  281. if( Endpoint->GroupType == GroupTypeConstrained ) {
  282. AfdInterlockedRemoveEntryList(
  283. &Endpoint->ConstrainedEndpointListEntry,
  284. &AfdSpinLock
  285. );
  286. }
  287. //
  288. // If the list of endpoints is now empty, do some deallocations.
  289. //
  290. if ( IsListEmpty( &AfdEndpointListHead ) ) {
  291. PAFD_WORK_ITEM afdWorkItem;
  292. //
  293. // Unlock the AFD section that can be pagable when no sockets
  294. // are open.
  295. //
  296. ASSERT( IsListEmpty( &AfdConstrainedEndpointListHead ) );
  297. ASSERT( AfdDiscardableCodeHandle != NULL );
  298. MmUnlockPagableImageSection( AfdDiscardableCodeHandle );
  299. AfdDiscardableCodeHandle = NULL;
  300. //
  301. // Queue off an executive worker thread to unlock AFD. We do
  302. // this using special hacks in the AFD worker thread code so
  303. // that we don't need to acuire a spin lock after the unlock.
  304. //
  305. afdWorkItem = AfdAllocateWorkItem();
  306. ASSERT( afdWorkItem != NULL );
  307. AfdQueueWorkItem( AfdUnlockDriver, afdWorkItem );
  308. }
  309. //
  310. // Release the lock and return.
  311. //
  312. ExReleaseResource( AfdResource );
  313. return;
  314. } // AfdRemoveEndpointFromList
  315. VOID
  316. AfdUnlockDriver (
  317. IN PVOID Context
  318. )
  319. {
  320. //
  321. // Free the work item allocated in AdfRemoveEndpointFromList().
  322. //
  323. AfdFreeWorkItem( (PAFD_WORK_ITEM)Context );
  324. //
  325. // Acquire a lock which prevents other threads from performing this
  326. // operation.
  327. //
  328. ExAcquireResourceExclusive( AfdResource, TRUE );
  329. //
  330. // Test whether the endpoint list remains empty. If it is still
  331. // empty, we can proceed with unlocking the driver. If a new
  332. // endpoint has been placed on the list, then do not make AFD
  333. // pagable.
  334. //
  335. if ( IsListEmpty( &AfdEndpointListHead ) ) {
  336. //
  337. // Tell MM that it can page all of AFD as it desires.
  338. //
  339. AfdLoaded = FALSE;
  340. MmPageEntireDriver( DriverEntry );
  341. }
  342. ExReleaseResource( AfdResource );
  343. } // AfdUnlockDriver
  344. VOID
  345. AfdInterlockedRemoveEntryList (
  346. IN PLIST_ENTRY ListEntry,
  347. IN PKSPIN_LOCK SpinLock
  348. )
  349. {
  350. KIRQL oldIrql;
  351. //
  352. // Our own routine since EX doesn't have a version of this....
  353. //
  354. AfdAcquireSpinLock( SpinLock, &oldIrql );
  355. RemoveEntryList( ListEntry );
  356. AfdReleaseSpinLock( SpinLock, oldIrql );
  357. } // AfdInterlockedRemoveEntryList
  358. NTSTATUS
  359. AfdQueryHandles (
  360. IN PIRP Irp,
  361. IN PIO_STACK_LOCATION IrpSp
  362. )
  363. /*++
  364. Routine Description:
  365. Returns information about the TDI handles corresponding to an AFD
  366. endpoint. NULL is returned for either the connection handle or the
  367. address handle (or both) if the endpoint does not have that particular
  368. object.
  369. Arguments:
  370. Irp - Pointer to I/O request packet.
  371. IrpSp - pointer to the IO stack location to use for this request.
  372. Return Value:
  373. NTSTATUS -- Indicates whether the request was successfully queued.
  374. --*/
  375. {
  376. PAFD_ENDPOINT endpoint;
  377. PAFD_HANDLE_INFO handleInfo;
  378. ULONG getHandleInfo;
  379. NTSTATUS status;
  380. PAGED_CODE( );
  381. //
  382. // Set up local pointers.
  383. //
  384. endpoint = IrpSp->FileObject->FsContext;
  385. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  386. handleInfo = Irp->AssociatedIrp.SystemBuffer;
  387. //
  388. // Make sure that the input and output buffers are large enough.
  389. //
  390. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  391. sizeof(getHandleInfo) ||
  392. IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  393. sizeof(*handleInfo) ) {
  394. return STATUS_BUFFER_TOO_SMALL;
  395. }
  396. //
  397. // Determine which handles we need to get.
  398. //
  399. getHandleInfo = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
  400. //
  401. // If no handle information or invalid handle information was
  402. // requested, fail.
  403. //
  404. if ( (getHandleInfo &
  405. ~(AFD_QUERY_ADDRESS_HANDLE | AFD_QUERY_CONNECTION_HANDLE)) != 0 ||
  406. getHandleInfo == 0 ) {
  407. return STATUS_INVALID_PARAMETER;
  408. }
  409. //
  410. // Initialize the output buffer.
  411. //
  412. handleInfo->TdiAddressHandle = NULL;
  413. handleInfo->TdiConnectionHandle = NULL;
  414. //
  415. // If the caller requested a TDI address handle and we have an
  416. // address handle for this endpoint, dupe the address handle to the
  417. // user process.
  418. //
  419. if ( (getHandleInfo & AFD_QUERY_ADDRESS_HANDLE) != 0 &&
  420. endpoint->State != AfdEndpointStateOpen &&
  421. endpoint->AddressHandle != NULL ) {
  422. ASSERT( endpoint->AddressFileObject != NULL );
  423. status = ObOpenObjectByPointer(
  424. endpoint->AddressFileObject,
  425. OBJ_CASE_INSENSITIVE,
  426. NULL,
  427. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  428. *IoFileObjectType,
  429. KernelMode,
  430. &handleInfo->TdiAddressHandle
  431. );
  432. if ( !NT_SUCCESS(status) ) {
  433. return status;
  434. }
  435. }
  436. //
  437. // If the caller requested a TDI connection handle and we have a
  438. // connection handle for this endpoint, dupe the connection handle
  439. // to the user process.
  440. //
  441. if ( (getHandleInfo & AFD_QUERY_CONNECTION_HANDLE) != 0 &&
  442. endpoint->Type == AfdBlockTypeVcConnecting &&
  443. endpoint->Common.VcConnecting.Connection != NULL &&
  444. endpoint->Common.VcConnecting.Connection->Handle != NULL ) {
  445. ASSERT( endpoint->Common.VcConnecting.Connection->Type == AfdBlockTypeConnection );
  446. ASSERT( endpoint->Common.VcConnecting.Connection->FileObject != NULL );
  447. status = ObOpenObjectByPointer(
  448. endpoint->Common.VcConnecting.Connection->FileObject,
  449. OBJ_CASE_INSENSITIVE,
  450. NULL,
  451. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  452. *IoFileObjectType,
  453. KernelMode,
  454. &handleInfo->TdiConnectionHandle
  455. );
  456. if ( !NT_SUCCESS(status) ) {
  457. if ( handleInfo->TdiAddressHandle != NULL ) {
  458. ZwClose( handleInfo->TdiAddressHandle );
  459. }
  460. return status;
  461. }
  462. }
  463. Irp->IoStatus.Information = sizeof(*handleInfo);
  464. return STATUS_SUCCESS;
  465. } // AfdQueryHandles
  466. NTSTATUS
  467. AfdGetInformation (
  468. IN PIRP Irp,
  469. IN PIO_STACK_LOCATION IrpSp
  470. )
  471. /*++
  472. Routine Description:
  473. Gets information in the endpoint.
  474. Arguments:
  475. Irp - Pointer to I/O request packet.
  476. IrpSp - pointer to the IO stack location to use for this request.
  477. Return Value:
  478. NTSTATUS -- Indicates whether the request was successfully queued.
  479. --*/
  480. {
  481. PAFD_ENDPOINT endpoint;
  482. PAFD_CONNECTION connection;
  483. PAFD_INFORMATION afdInfo;
  484. PVOID additionalInfo;
  485. ULONG additionalInfoLength;
  486. TDI_REQUEST_KERNEL_QUERY_INFORMATION kernelQueryInfo;
  487. TDI_CONNECTION_INFORMATION connectionInfo;
  488. NTSTATUS status;
  489. LONGLONG currentTime;
  490. LONGLONG connectTime;
  491. PAGED_CODE( );
  492. //
  493. // Set up local pointers.
  494. //
  495. endpoint = IrpSp->FileObject->FsContext;
  496. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  497. afdInfo = Irp->AssociatedIrp.SystemBuffer;
  498. //
  499. // Make sure that the input and output buffers are large enough.
  500. //
  501. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  502. sizeof(*afdInfo) ||
  503. IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  504. sizeof(*afdInfo) ) {
  505. return STATUS_BUFFER_TOO_SMALL;
  506. }
  507. //
  508. // Figure out the additional information, if any.
  509. //
  510. additionalInfo = afdInfo + 1;
  511. additionalInfoLength =
  512. IrpSp->Parameters.DeviceIoControl.InputBufferLength - sizeof(*afdInfo);
  513. //
  514. // Set up appropriate information in the endpoint.
  515. //
  516. switch ( afdInfo->InformationType ) {
  517. case AFD_MAX_PATH_SEND_SIZE:
  518. //
  519. // Set up a query to the TDI provider to obtain the largest
  520. // datagram that can be sent to a particular address.
  521. //
  522. kernelQueryInfo.QueryType = TDI_QUERY_MAX_DATAGRAM_INFO;
  523. kernelQueryInfo.RequestConnectionInformation = &connectionInfo;
  524. connectionInfo.UserDataLength = 0;
  525. connectionInfo.UserData = NULL;
  526. connectionInfo.OptionsLength = 0;
  527. connectionInfo.Options = NULL;
  528. connectionInfo.RemoteAddressLength = additionalInfoLength;
  529. connectionInfo.RemoteAddress = additionalInfo;
  530. //
  531. // Ask the TDI provider for the information.
  532. //
  533. status = AfdIssueDeviceControl(
  534. NULL,
  535. endpoint->AddressFileObject,
  536. &kernelQueryInfo,
  537. sizeof(kernelQueryInfo),
  538. &afdInfo->Information.Ulong,
  539. sizeof(afdInfo->Information.Ulong),
  540. TDI_QUERY_INFORMATION
  541. );
  542. //
  543. // If the request succeeds, use this information. Otherwise,
  544. // fall through and use the transport's global information.
  545. // This is done because not all transports support this
  546. // particular TDI request, and for those which do not the
  547. // global information is a reasonable approximation.
  548. //
  549. if ( NT_SUCCESS(status) ) {
  550. break;
  551. }
  552. case AFD_MAX_SEND_SIZE:
  553. //
  554. // Return the MaxSendSize or MaxDatagramSendSize from the
  555. // TDI_PROVIDER_INFO based on whether or not this is a datagram
  556. // endpoint.
  557. //
  558. if ( IS_DGRAM_ENDPOINT(endpoint) ) {
  559. afdInfo->Information.Ulong =
  560. endpoint->TransportInfo->ProviderInfo.MaxDatagramSize;
  561. } else {
  562. afdInfo->Information.Ulong =
  563. endpoint->TransportInfo->ProviderInfo.MaxSendSize;
  564. }
  565. break;
  566. case AFD_SENDS_PENDING:
  567. //
  568. // If this is an endpoint on a bufferring transport, no sends
  569. // are pending in AFD. If it is on a nonbufferring transport,
  570. // return the count of sends pended in AFD.
  571. //
  572. if ( endpoint->TdiBufferring || endpoint->Type != AfdBlockTypeVcConnecting ) {
  573. afdInfo->Information.Ulong = 0;
  574. } else {
  575. afdInfo->Information.Ulong =
  576. endpoint->Common.VcConnecting.Connection->VcBufferredSendCount;
  577. }
  578. break;
  579. case AFD_RECEIVE_WINDOW_SIZE:
  580. //
  581. // Return the default receive window.
  582. //
  583. afdInfo->Information.Ulong = AfdReceiveWindowSize;
  584. break;
  585. case AFD_SEND_WINDOW_SIZE:
  586. //
  587. // Return the default send window.
  588. //
  589. afdInfo->Information.Ulong = AfdSendWindowSize;
  590. break;
  591. case AFD_CONNECT_TIME:
  592. //
  593. // If the endpoint is not yet connected, return -1. Otherwise,
  594. // calculate the number of seconds that the connection has been
  595. // active.
  596. //
  597. if ( endpoint->State != AfdEndpointStateConnected ||
  598. endpoint->EndpointType == AfdEndpointTypeDatagram ) {
  599. afdInfo->Information.Ulong = 0xFFFFFFFF;
  600. } else {
  601. connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
  602. ASSERT( connection != NULL );
  603. ASSERT( connection->Type == AfdBlockTypeConnection );
  604. //
  605. // Calculate how long the connection has been active by
  606. // subtracting the time at which the connection started from
  607. // the current time. Note that we convert the units of the
  608. // time value from 100s of nanoseconds to seconds.
  609. //
  610. KeQuerySystemTime( (PLARGE_INTEGER)&currentTime );
  611. connectTime = (currentTime - connection->ConnectTime);
  612. connectTime /= 10*1000*1000;
  613. //
  614. // We can safely convert this to a ULONG because it takes
  615. // 127 years to overflow a ULONG counting seconds. The
  616. // bizarre conversion to a LARGE_INTEGER is required to
  617. // prevent the compiler from optimizing out the full 64-bit
  618. // division above. Without this, the compiler would do only
  619. // a 32-bit division and lose some information.
  620. //
  621. //afdInfo->Information.Ulong = (ULONG)connectTime;
  622. afdInfo->Information.Ulong = ((PLARGE_INTEGER)&connectTime)->LowPart;
  623. }
  624. break;
  625. case AFD_GROUP_ID_AND_TYPE : {
  626. PAFD_GROUP_INFO groupInfo;
  627. groupInfo = (PAFD_GROUP_INFO)&afdInfo->Information.LargeInteger;
  628. //
  629. // Return the endpoint's group ID and group type.
  630. //
  631. groupInfo->GroupID = endpoint->GroupID;
  632. groupInfo->GroupType = endpoint->GroupType;
  633. }
  634. break;
  635. default:
  636. return STATUS_INVALID_PARAMETER;
  637. }
  638. Irp->IoStatus.Information = sizeof(*afdInfo);
  639. Irp->IoStatus.Status = STATUS_SUCCESS;
  640. return STATUS_SUCCESS;
  641. } // AfdGetInformation
  642. NTSTATUS
  643. AfdSetInformation (
  644. IN PIRP Irp,
  645. IN PIO_STACK_LOCATION IrpSp
  646. )
  647. /*++
  648. Routine Description:
  649. Sets information in the endpoint.
  650. Arguments:
  651. Irp - Pointer to I/O request packet.
  652. IrpSp - pointer to the IO stack location to use for this request.
  653. Return Value:
  654. NTSTATUS -- Indicates whether the request was successfully queued.
  655. --*/
  656. {
  657. PAFD_ENDPOINT endpoint;
  658. PAFD_CONNECTION connection;
  659. PAFD_INFORMATION afdInfo;
  660. NTSTATUS status;
  661. PAGED_CODE( );
  662. //
  663. // Set up local pointers.
  664. //
  665. endpoint = IrpSp->FileObject->FsContext;
  666. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  667. afdInfo = Irp->AssociatedIrp.SystemBuffer;
  668. //
  669. // Make sure that the input buffer is large enough.
  670. //
  671. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*afdInfo) ) {
  672. return STATUS_BUFFER_TOO_SMALL;
  673. }
  674. //
  675. // Set up appropriate information in the endpoint.
  676. //
  677. switch ( afdInfo->InformationType ) {
  678. case AFD_NONBLOCKING_MODE:
  679. //
  680. // Set the blocking mode of the endpoint. If TRUE, send and receive
  681. // calls on the endpoint will fail if they cannot be completed
  682. // immediately.
  683. //
  684. endpoint->NonBlocking = afdInfo->Information.Boolean;
  685. break;
  686. case AFD_CIRCULAR_QUEUEING:
  687. //
  688. // Enables circular queuing on the endpoint.
  689. //
  690. if( !IS_DGRAM_ENDPOINT( endpoint ) ) {
  691. return STATUS_INVALID_PARAMETER;
  692. }
  693. endpoint->Common.Datagram.CircularQueueing = afdInfo->Information.Boolean;
  694. break;
  695. case AFD_INLINE_MODE:
  696. //
  697. // Set the inline mode of the endpoint. If TRUE, a receive for
  698. // normal data will be completed with either normal data or
  699. // expedited data. If the endpoint is connected, we need to
  700. // tell the TDI provider that the endpoint is inline so that it
  701. // delivers data to us in order. If the endpoint is not yet
  702. // connected, then we will set the inline mode when we create
  703. // the TDI connection object.
  704. //
  705. if ( endpoint->Type == AfdBlockTypeVcConnecting ) {
  706. status = AfdSetInLineMode(
  707. AFD_CONNECTION_FROM_ENDPOINT( endpoint ),
  708. afdInfo->Information.Boolean
  709. );
  710. if ( !NT_SUCCESS(status) ) {
  711. return status;
  712. }
  713. }
  714. endpoint->InLine = afdInfo->Information.Boolean;
  715. break;
  716. case AFD_RECEIVE_WINDOW_SIZE:
  717. case AFD_SEND_WINDOW_SIZE: {
  718. LONG newBytes;
  719. PCLONG maxBytes;
  720. CLONG requestedCount;
  721. PCSHORT maxCount;
  722. #ifdef AFDDBG_QUOTA
  723. PVOID chargeBlock;
  724. PSZ chargeType;
  725. #endif
  726. //
  727. // First determine where the appropriate limits are stored in the
  728. // connection or endpoint. We do this so that we can use common
  729. // code to charge quota and set the new counters.
  730. //
  731. if ( endpoint->Type == AfdBlockTypeVcConnecting ) {
  732. connection = endpoint->Common.VcConnecting.Connection;
  733. if ( afdInfo->InformationType == AFD_SEND_WINDOW_SIZE ) {
  734. maxBytes = &connection->MaxBufferredSendBytes;
  735. maxCount = &connection->MaxBufferredSendCount;
  736. } else {
  737. maxBytes = &connection->MaxBufferredReceiveBytes;
  738. maxCount = &connection->MaxBufferredReceiveCount;
  739. }
  740. #ifdef AFDDBG_QUOTA
  741. chargeBlock = connection;
  742. chargeType = "SetInfo vcnb";
  743. #endif
  744. } else if ( endpoint->Type == AfdBlockTypeDatagram ) {
  745. if ( afdInfo->InformationType == AFD_SEND_WINDOW_SIZE ) {
  746. maxBytes = &endpoint->Common.Datagram.MaxBufferredSendBytes;
  747. maxCount = &endpoint->Common.Datagram.MaxBufferredSendCount;
  748. } else {
  749. maxBytes = &endpoint->Common.Datagram.MaxBufferredReceiveBytes;
  750. maxCount = &endpoint->Common.Datagram.MaxBufferredReceiveCount;
  751. }
  752. #ifdef AFDDBG_QUOTA
  753. chargeBlock = endpoint;
  754. chargeType = "SetInfo dgrm";
  755. #endif
  756. } else {
  757. return STATUS_INVALID_PARAMETER;
  758. }
  759. //
  760. // Make sure that we always allow at least one message to be
  761. // bufferred on an endpoint.
  762. //
  763. requestedCount = afdInfo->Information.Ulong / AfdBufferMultiplier;
  764. if ( requestedCount == 0 ) {
  765. //
  766. // Don't allow the max receive bytes to go to zero, but
  767. // max send bytes IS allowed to go to zero because it has
  768. // special meaning: specifically, do not buffer sends.
  769. //
  770. if ( afdInfo->InformationType == AFD_RECEIVE_WINDOW_SIZE ) {
  771. afdInfo->Information.Ulong = AfdBufferMultiplier;
  772. requestedCount = 1;
  773. }
  774. }
  775. //
  776. // If the count will overflow the field we use to set the max
  777. // count, just use the max count as the limit.
  778. //
  779. if ( requestedCount > 0x7FFF ) {
  780. requestedCount = 0x7FFF;
  781. }
  782. //
  783. // Charge or return quota to the process making this request.
  784. //
  785. newBytes = afdInfo->Information.Ulong - (ULONG)(*maxBytes);
  786. if ( newBytes > 0 ) {
  787. try {
  788. PsChargePoolQuota(
  789. endpoint->OwningProcess,
  790. NonPagedPool,
  791. newBytes
  792. );
  793. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  794. #if DBG
  795. DbgPrint( "AfdSetInformation: PsChargePoolQuota failed.\n" );
  796. #endif
  797. return STATUS_QUOTA_EXCEEDED;
  798. }
  799. AfdRecordQuotaHistory(
  800. endpoint->OwningProcess,
  801. newBytes,
  802. chargeType,
  803. chargeBlock
  804. );
  805. AfdRecordPoolQuotaCharged( newBytes );
  806. } else {
  807. PsReturnPoolQuota(
  808. endpoint->OwningProcess,
  809. NonPagedPool,
  810. -1 * newBytes
  811. );
  812. AfdRecordQuotaHistory(
  813. endpoint->OwningProcess,
  814. newBytes,
  815. chargeType,
  816. chargeBlock
  817. );
  818. AfdRecordPoolQuotaCharged( -1 * newBytes );
  819. }
  820. //
  821. // Set up the new information in the AFD internal structure.
  822. //
  823. *maxBytes = (CLONG)afdInfo->Information.Ulong;
  824. *maxCount = (CSHORT)requestedCount;
  825. break;
  826. }
  827. default:
  828. return STATUS_INVALID_PARAMETER;
  829. }
  830. return STATUS_SUCCESS;
  831. } // AfdSetInformation
  832. NTSTATUS
  833. AfdSetInLineMode (
  834. IN PAFD_CONNECTION Connection,
  835. IN BOOLEAN InLine
  836. )
  837. /*++
  838. Routine Description:
  839. Sets a connection to be in inline mode. In inline mode, urgent data
  840. is delivered in the order in which it is received. We must tell the
  841. TDI provider about this so that it indicates data in the proper
  842. order.
  843. Arguments:
  844. Connection - the AFD connection to set as inline.
  845. InLine - TRUE to enable inline mode, FALSE to disable inline mode.
  846. Return Value:
  847. NTSTATUS -- Indicates whether the request was successfully
  848. performed.
  849. --*/
  850. {
  851. NTSTATUS status;
  852. PTCP_REQUEST_SET_INFORMATION_EX setInfoEx;
  853. PIO_STATUS_BLOCK ioStatusBlock;
  854. HANDLE event;
  855. PAGED_CODE( );
  856. //
  857. // Allocate space to hold the TDI set information buffers and the IO
  858. // status block.
  859. //
  860. ioStatusBlock = AFD_ALLOCATE_POOL(
  861. NonPagedPool,
  862. sizeof(*ioStatusBlock) + sizeof(*setInfoEx) +
  863. sizeof(TCPSocketOption),
  864. AFD_INLINE_POOL_TAG
  865. );
  866. if ( ioStatusBlock == NULL ) {
  867. return STATUS_INSUFFICIENT_RESOURCES;
  868. }
  869. //
  870. // Initialize the TDI information buffers.
  871. //
  872. setInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)(ioStatusBlock + 1);
  873. setInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
  874. setInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  875. setInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  876. setInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
  877. setInfoEx->ID.toi_id = TCP_SOCKET_OOBINLINE;
  878. *(PULONG)setInfoEx->Buffer = (ULONG)InLine;
  879. setInfoEx->BufferSize = sizeof(ULONG);
  880. KeAttachProcess( AfdSystemProcess );
  881. status = ZwCreateEvent(
  882. &event,
  883. EVENT_ALL_ACCESS,
  884. NULL,
  885. SynchronizationEvent,
  886. FALSE
  887. );
  888. if ( !NT_SUCCESS(status) ) {
  889. KeDetachProcess( );
  890. AFD_FREE_POOL(
  891. ioStatusBlock,
  892. AFD_INLINE_POOL_TAG
  893. );
  894. return status;
  895. }
  896. //
  897. // Make the actual TDI set information call.
  898. //
  899. status = ZwDeviceIoControlFile(
  900. Connection->Handle,
  901. event,
  902. NULL,
  903. NULL,
  904. ioStatusBlock,
  905. IOCTL_TCP_SET_INFORMATION_EX,
  906. setInfoEx,
  907. sizeof(*setInfoEx) + setInfoEx->BufferSize,
  908. NULL,
  909. 0
  910. );
  911. if ( status == STATUS_PENDING ) {
  912. status = ZwWaitForSingleObject( event, FALSE, NULL );
  913. ASSERT( NT_SUCCESS(status) );
  914. status = ioStatusBlock->Status;
  915. }
  916. ZwClose( event );
  917. KeDetachProcess( );
  918. AFD_FREE_POOL(
  919. ioStatusBlock,
  920. AFD_INLINE_POOL_TAG
  921. );
  922. //
  923. // Since this option is only supported for TCP/IP, always return success.
  924. //
  925. return STATUS_SUCCESS;
  926. } // AfdSetInLineMode
  927. NTSTATUS
  928. AfdGetContext (
  929. IN PIRP Irp,
  930. IN PIO_STACK_LOCATION IrpSp
  931. )
  932. {
  933. PAFD_ENDPOINT endpoint;
  934. PAGED_CODE( );
  935. //
  936. // Set up local pointers.
  937. //
  938. endpoint = IrpSp->FileObject->FsContext;
  939. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  940. //
  941. // Make sure that the output buffer is large enough to hold all the
  942. // context information for this socket.
  943. //
  944. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  945. endpoint->ContextLength ) {
  946. return STATUS_BUFFER_TOO_SMALL;
  947. }
  948. //
  949. // If there is no context, return nothing.
  950. //
  951. if ( endpoint->Context == NULL ) {
  952. Irp->IoStatus.Information = 0;
  953. return STATUS_SUCCESS;
  954. }
  955. //
  956. // Return the context information we have stored for this endpoint.
  957. //
  958. RtlCopyMemory(
  959. Irp->AssociatedIrp.SystemBuffer,
  960. endpoint->Context,
  961. endpoint->ContextLength
  962. );
  963. Irp->IoStatus.Information = endpoint->ContextLength;
  964. return STATUS_SUCCESS;
  965. } // AfdGetContext
  966. NTSTATUS
  967. AfdGetContextLength (
  968. IN PIRP Irp,
  969. IN PIO_STACK_LOCATION IrpSp
  970. )
  971. {
  972. PAFD_ENDPOINT endpoint;
  973. PAGED_CODE( );
  974. //
  975. // Set up local pointers.
  976. //
  977. endpoint = IrpSp->FileObject->FsContext;
  978. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  979. //
  980. // Make sure that the output buffer is large enough to hold the
  981. // context buffer length.
  982. //
  983. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  984. sizeof(endpoint->ContextLength) ) {
  985. return STATUS_BUFFER_TOO_SMALL;
  986. }
  987. //
  988. // Return the length of the context information we have stored for
  989. // this endpoint.
  990. //
  991. *(PULONG)Irp->AssociatedIrp.SystemBuffer = endpoint->ContextLength;
  992. Irp->IoStatus.Information = sizeof(endpoint->ContextLength);
  993. return STATUS_SUCCESS;
  994. } // AfdGetContextLength
  995. NTSTATUS
  996. AfdSetContext (
  997. IN PIRP Irp,
  998. IN PIO_STACK_LOCATION IrpSp
  999. )
  1000. {
  1001. PAFD_ENDPOINT endpoint;
  1002. ULONG newContextLength;
  1003. PAGED_CODE( );
  1004. //
  1005. // Set up local pointers.
  1006. //
  1007. endpoint = IrpSp->FileObject->FsContext;
  1008. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1009. newContextLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  1010. //
  1011. // If there is no context buffer on the endpoint, or if the context
  1012. // buffer is too small, allocate a new context buffer from paged pool.
  1013. //
  1014. if ( endpoint->Context == NULL ||
  1015. endpoint->ContextLength < newContextLength ) {
  1016. PVOID newContext;
  1017. //
  1018. // Allocate a new context buffer.
  1019. //
  1020. try {
  1021. newContext = AFD_ALLOCATE_POOL_WITH_QUOTA(
  1022. PagedPool,
  1023. newContextLength,
  1024. AFD_CONTEXT_POOL_TAG
  1025. );
  1026. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1027. return STATUS_INSUFFICIENT_RESOURCES;
  1028. }
  1029. if ( newContext == NULL ) {
  1030. return STATUS_INSUFFICIENT_RESOURCES;
  1031. }
  1032. //
  1033. // Free the old context buffer, if there was one.
  1034. //
  1035. if ( endpoint->Context != NULL ) {
  1036. AFD_FREE_POOL(
  1037. endpoint->Context,
  1038. AFD_CONTEXT_POOL_TAG
  1039. );
  1040. }
  1041. endpoint->Context = newContext;
  1042. }
  1043. //
  1044. // Store the passed-in context buffer.
  1045. //
  1046. endpoint->ContextLength = newContextLength;
  1047. RtlCopyMemory(
  1048. endpoint->Context,
  1049. Irp->AssociatedIrp.SystemBuffer,
  1050. newContextLength
  1051. );
  1052. Irp->IoStatus.Information = 0;
  1053. return STATUS_SUCCESS;
  1054. } // AfdSetContext
  1055. NTSTATUS
  1056. AfdSetEventHandler (
  1057. IN PFILE_OBJECT FileObject,
  1058. IN ULONG EventType,
  1059. IN PVOID EventHandler,
  1060. IN PVOID EventContext
  1061. )
  1062. /*++
  1063. Routine Description:
  1064. Sets up a TDI indication handler on a connection or address object
  1065. (depending on the file handle). This is done synchronously, which
  1066. shouldn't usually be an issue since TDI providers can usually complete
  1067. indication handler setups immediately.
  1068. Arguments:
  1069. FileObject - a pointer to the file object for an open connection or
  1070. address object.
  1071. EventType - the event for which the indication handler should be
  1072. called.
  1073. EventHandler - the routine to call when tghe specified event occurs.
  1074. EventContext - context which is passed to the indication routine.
  1075. Return Value:
  1076. NTSTATUS -- Indicates the status of the request.
  1077. --*/
  1078. {
  1079. TDI_REQUEST_KERNEL_SET_EVENT parameters;
  1080. PAGED_CODE( );
  1081. parameters.EventType = EventType;
  1082. parameters.EventHandler = EventHandler;
  1083. parameters.EventContext = EventContext;
  1084. return AfdIssueDeviceControl(
  1085. NULL,
  1086. FileObject,
  1087. &parameters,
  1088. sizeof(parameters),
  1089. NULL,
  1090. 0,
  1091. TDI_SET_EVENT_HANDLER
  1092. );
  1093. } // AfdSetEventHandler
  1094. NTSTATUS
  1095. AfdIssueDeviceControl (
  1096. IN HANDLE FileHandle OPTIONAL,
  1097. IN PFILE_OBJECT FileObject OPTIONAL,
  1098. IN PVOID IrpParameters,
  1099. IN ULONG IrpParametersLength,
  1100. IN PVOID MdlBuffer,
  1101. IN ULONG MdlBufferLength,
  1102. IN UCHAR MinorFunction
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. Issues a device control returst to a TDI provider and waits for the
  1107. request to complete.
  1108. Note that while FileHandle and FileObject are both marked as optional,
  1109. in reality exactly one of these must be specified.
  1110. Arguments:
  1111. FileHandle - a TDI handle.
  1112. FileObject - a pointer to the file object corresponding to a TDI
  1113. handle
  1114. IrpParameters - information to write to the parameters section of the
  1115. stack location of the IRP.
  1116. IrpParametersLength - length of the parameter information. Cannot be
  1117. greater than 16.
  1118. MdlBuffer - if non-NULL, a buffer of nonpaged pool to be mapped
  1119. into an MDL and placed in the MdlAddress field of the IRP.
  1120. MdlBufferLength - the size of the buffer pointed to by MdlBuffer.
  1121. MinorFunction - the minor function code for the request.
  1122. Return Value:
  1123. NTSTATUS -- Indicates the status of the request.
  1124. --*/
  1125. {
  1126. NTSTATUS status;
  1127. PFILE_OBJECT fileObject;
  1128. PIRP irp;
  1129. PIO_STACK_LOCATION irpSp;
  1130. KEVENT event;
  1131. IO_STATUS_BLOCK ioStatusBlock;
  1132. PDEVICE_OBJECT deviceObject;
  1133. PMDL mdl;
  1134. PAGED_CODE( );
  1135. //
  1136. // Initialize the kernel event that will signal I/O completion.
  1137. //
  1138. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  1139. if( FileHandle != NULL ) {
  1140. ASSERT( FileObject == NULL );
  1141. //
  1142. // Get the file object corresponding to the directory's handle.
  1143. // Referencing the file object every time is necessary because the
  1144. // IO completion routine dereferences it.
  1145. //
  1146. status = ObReferenceObjectByHandle(
  1147. FileHandle,
  1148. 0L, // DesiredAccess
  1149. NULL, // ObjectType
  1150. KernelMode,
  1151. (PVOID *)&fileObject,
  1152. NULL
  1153. );
  1154. if ( !NT_SUCCESS(status) ) {
  1155. return status;
  1156. }
  1157. } else {
  1158. ASSERT( FileObject != NULL );
  1159. //
  1160. // Reference the passed in file object. This is necessary because
  1161. // the IO completion routine dereferences it.
  1162. //
  1163. ObReferenceObject( FileObject );
  1164. fileObject = FileObject;
  1165. }
  1166. //
  1167. // Set the file object event to a non-signaled state.
  1168. //
  1169. (VOID) KeResetEvent( &fileObject->Event );
  1170. //
  1171. // Attempt to allocate and initialize the I/O Request Packet (IRP)
  1172. // for this operation.
  1173. //
  1174. deviceObject = IoGetRelatedDeviceObject ( fileObject );
  1175. irp = IoAllocateIrp( (deviceObject)->StackSize, TRUE );
  1176. if ( irp == NULL ) {
  1177. ObDereferenceObject( fileObject );
  1178. return STATUS_INSUFFICIENT_RESOURCES;
  1179. }
  1180. //
  1181. // Fill in the service independent parameters in the IRP.
  1182. //
  1183. irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
  1184. irp->RequestorMode = KernelMode;
  1185. irp->PendingReturned = FALSE;
  1186. irp->UserIosb = &ioStatusBlock;
  1187. irp->UserEvent = &event;
  1188. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  1189. irp->AssociatedIrp.SystemBuffer = NULL;
  1190. irp->UserBuffer = NULL;
  1191. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1192. irp->Tail.Overlay.OriginalFileObject = fileObject;
  1193. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  1194. DEBUG ioStatusBlock.Status = STATUS_UNSUCCESSFUL;
  1195. DEBUG ioStatusBlock.Information = (ULONG)-1;
  1196. //
  1197. // If an MDL buffer was specified, get an MDL, map the buffer,
  1198. // and place the MDL pointer in the IRP.
  1199. //
  1200. if ( MdlBuffer != NULL ) {
  1201. mdl = IoAllocateMdl(
  1202. MdlBuffer,
  1203. MdlBufferLength,
  1204. FALSE,
  1205. FALSE,
  1206. irp
  1207. );
  1208. if ( mdl == NULL ) {
  1209. IoFreeIrp( irp );
  1210. ObDereferenceObject( fileObject );
  1211. return STATUS_INSUFFICIENT_RESOURCES;
  1212. }
  1213. MmBuildMdlForNonPagedPool( mdl );
  1214. } else {
  1215. irp->MdlAddress = NULL;
  1216. }
  1217. //
  1218. // Put the file object pointer in the stack location.
  1219. //
  1220. irpSp = IoGetNextIrpStackLocation( irp );
  1221. irpSp->FileObject = fileObject;
  1222. irpSp->DeviceObject = deviceObject;
  1223. //
  1224. // Fill in the service-dependent parameters for the request.
  1225. //
  1226. ASSERT( IrpParametersLength <= sizeof(irpSp->Parameters) );
  1227. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  1228. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1229. irpSp->MinorFunction = MinorFunction;
  1230. //
  1231. // Set up a completion routine which we'll use to free the MDL
  1232. // allocated previously.
  1233. //
  1234. IoSetCompletionRoutine( irp, AfdRestartDeviceControl, NULL, TRUE, TRUE, TRUE );
  1235. //
  1236. // Queue the IRP to the thread and pass it to the driver.
  1237. //
  1238. IoEnqueueIrp( irp );
  1239. status = IoCallDriver( deviceObject, irp );
  1240. //
  1241. // If necessary, wait for the I/O to complete.
  1242. //
  1243. if ( status == STATUS_PENDING ) {
  1244. KeWaitForSingleObject( (PVOID)&event, UserRequest, KernelMode, FALSE, NULL );
  1245. }
  1246. //
  1247. // If the request was successfully queued, get the final I/O status.
  1248. //
  1249. if ( NT_SUCCESS(status) ) {
  1250. status = ioStatusBlock.Status;
  1251. }
  1252. return status;
  1253. } // AfdIssueDeviceControl
  1254. NTSTATUS
  1255. AfdRestartDeviceControl (
  1256. IN PDEVICE_OBJECT DeviceObject,
  1257. IN PIRP Irp,
  1258. IN PVOID Context
  1259. )
  1260. {
  1261. //
  1262. // N.B. This routine can never be demand paged because it can be
  1263. // called before any endpoints have been placed on the global
  1264. // list--see AfdAllocateEndpoint() and it's call to
  1265. // AfdGetTransportInfo().
  1266. //
  1267. //
  1268. // If there was an MDL in the IRP, free it and reset the pointer to
  1269. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  1270. // in an IRP, which is why we do it here.
  1271. //
  1272. if ( Irp->MdlAddress != NULL ) {
  1273. IoFreeMdl( Irp->MdlAddress );
  1274. Irp->MdlAddress = NULL;
  1275. }
  1276. return STATUS_SUCCESS;
  1277. } // AfdRestartDeviceControl
  1278. NTSTATUS
  1279. AfdGetConnectData (
  1280. IN PIRP Irp,
  1281. IN PIO_STACK_LOCATION IrpSp,
  1282. IN ULONG Code
  1283. )
  1284. {
  1285. PAFD_ENDPOINT endpoint;
  1286. PAFD_CONNECTION connection;
  1287. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  1288. PAFD_CONNECT_DATA_INFO connectDataInfo;
  1289. KIRQL oldIrql;
  1290. //
  1291. // Set up local pointers.
  1292. //
  1293. endpoint = IrpSp->FileObject->FsContext;
  1294. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1295. connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
  1296. ASSERT( connection == NULL || connection->Type == AfdBlockTypeConnection );
  1297. //
  1298. // If there is a connection on this endpoint, use the data buffers
  1299. // on the connection. Otherwise, use the data buffers from the
  1300. // endpoint.
  1301. //
  1302. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  1303. if ( connection != NULL ) {
  1304. connectDataBuffers = connection->ConnectDataBuffers;
  1305. } else {
  1306. connectDataBuffers = endpoint->ConnectDataBuffers;
  1307. }
  1308. //
  1309. // If there are no connect data buffers on the endpoint, complete
  1310. // the IRP with no bytes.
  1311. //
  1312. if ( connectDataBuffers == NULL ) {
  1313. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1314. Irp->IoStatus.Information = 0;
  1315. return STATUS_SUCCESS;
  1316. }
  1317. //
  1318. // Determine what sort of data we're handling and where it should
  1319. // come from.
  1320. //
  1321. switch ( Code ) {
  1322. case IOCTL_AFD_GET_CONNECT_DATA:
  1323. connectDataInfo = &connectDataBuffers->ReceiveConnectData;
  1324. break;
  1325. case IOCTL_AFD_GET_CONNECT_OPTIONS:
  1326. connectDataInfo = &connectDataBuffers->ReceiveConnectOptions;
  1327. break;
  1328. case IOCTL_AFD_GET_DISCONNECT_DATA:
  1329. connectDataInfo = &connectDataBuffers->ReceiveDisconnectData;
  1330. break;
  1331. case IOCTL_AFD_GET_DISCONNECT_OPTIONS:
  1332. connectDataInfo = &connectDataBuffers->ReceiveDisconnectOptions;
  1333. break;
  1334. default:
  1335. ASSERT(FALSE);
  1336. }
  1337. //
  1338. // If there is none of the requested data type, again complete
  1339. // the IRP with no bytes.
  1340. //
  1341. if ( connectDataInfo->Buffer == NULL ||
  1342. connectDataInfo->BufferLength == 0 ) {
  1343. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1344. Irp->IoStatus.Information = 0;
  1345. return STATUS_SUCCESS;
  1346. }
  1347. //
  1348. // If the output buffer is too small, fail.
  1349. //
  1350. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1351. connectDataInfo->BufferLength ) {
  1352. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1353. return STATUS_BUFFER_TOO_SMALL;
  1354. }
  1355. //
  1356. // Copy over the buffer and return the number of bytes copied.
  1357. //
  1358. RtlCopyMemory(
  1359. Irp->AssociatedIrp.SystemBuffer,
  1360. connectDataInfo->Buffer,
  1361. connectDataInfo->BufferLength
  1362. );
  1363. Irp->IoStatus.Information = connectDataInfo->BufferLength;
  1364. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1365. return STATUS_SUCCESS;
  1366. } // AfdGetConnectData
  1367. NTSTATUS
  1368. AfdSetConnectData (
  1369. IN PIRP Irp,
  1370. IN PIO_STACK_LOCATION IrpSp,
  1371. IN ULONG Code
  1372. )
  1373. {
  1374. PAFD_ENDPOINT endpoint;
  1375. PAFD_CONNECTION connection;
  1376. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  1377. PAFD_CONNECT_DATA_BUFFERS * connectDataBuffersTarget;
  1378. PAFD_CONNECT_DATA_INFO connectDataInfo;
  1379. KIRQL oldIrql;
  1380. ULONG bufferLength;
  1381. BOOLEAN size = FALSE;
  1382. //
  1383. // Set up local pointers.
  1384. //
  1385. endpoint = IrpSp->FileObject->FsContext;
  1386. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  1387. connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
  1388. ASSERT( connection == NULL || connection->Type == AfdBlockTypeConnection );
  1389. //
  1390. // If there is a connection on this endpoint, use the data buffers
  1391. // on the connection. Otherwise, use the data buffers from the
  1392. // endpoint. Also, if there is no connect data buffer structure
  1393. // yet, allocate one.
  1394. //
  1395. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  1396. if( connection != NULL ) {
  1397. connectDataBuffersTarget = &connection->ConnectDataBuffers;
  1398. } else {
  1399. connectDataBuffersTarget = &endpoint->ConnectDataBuffers;
  1400. }
  1401. connectDataBuffers = *connectDataBuffersTarget;
  1402. if( connectDataBuffers == NULL ) {
  1403. try {
  1404. connectDataBuffers = AFD_ALLOCATE_POOL_WITH_QUOTA(
  1405. NonPagedPool,
  1406. sizeof(*connectDataBuffers),
  1407. AFD_CONNECT_DATA_POOL_TAG
  1408. );
  1409. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1410. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1411. return STATUS_INSUFFICIENT_RESOURCES;
  1412. }
  1413. if( connectDataBuffers == NULL ) {
  1414. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1415. return STATUS_INSUFFICIENT_RESOURCES;
  1416. }
  1417. RtlZeroMemory(
  1418. connectDataBuffers,
  1419. sizeof(*connectDataBuffers)
  1420. );
  1421. *connectDataBuffersTarget = connectDataBuffers;
  1422. }
  1423. //
  1424. // If there is a connect outstanding on this endpoint or if it
  1425. // has already been shut down, fail this request. This prevents
  1426. // the connect code from accessing buffers which may be freed soon.
  1427. //
  1428. if( endpoint->ConnectOutstanding ||
  1429. (endpoint->DisconnectMode & ~AFD_PARTIAL_DISCONNECT_RECEIVE) != 0 ) {
  1430. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1431. return STATUS_INVALID_PARAMETER;
  1432. }
  1433. //
  1434. // Determine what sort of data we're handling and where it should
  1435. // go.
  1436. //
  1437. switch( Code ) {
  1438. case IOCTL_AFD_SET_CONNECT_DATA:
  1439. connectDataInfo = &connectDataBuffers->SendConnectData;
  1440. break;
  1441. case IOCTL_AFD_SET_CONNECT_OPTIONS:
  1442. connectDataInfo = &connectDataBuffers->SendConnectOptions;
  1443. break;
  1444. case IOCTL_AFD_SET_DISCONNECT_DATA:
  1445. connectDataInfo = &connectDataBuffers->SendDisconnectData;
  1446. break;
  1447. case IOCTL_AFD_SET_DISCONNECT_OPTIONS:
  1448. connectDataInfo = &connectDataBuffers->SendDisconnectOptions;
  1449. break;
  1450. case IOCTL_AFD_SIZE_CONNECT_DATA:
  1451. connectDataInfo = &connectDataBuffers->ReceiveConnectData;
  1452. size = TRUE;
  1453. break;
  1454. case IOCTL_AFD_SIZE_CONNECT_OPTIONS:
  1455. connectDataInfo = &connectDataBuffers->ReceiveConnectOptions;
  1456. size = TRUE;
  1457. break;
  1458. case IOCTL_AFD_SIZE_DISCONNECT_DATA:
  1459. connectDataInfo = &connectDataBuffers->ReceiveDisconnectData;
  1460. size = TRUE;
  1461. break;
  1462. case IOCTL_AFD_SIZE_DISCONNECT_OPTIONS:
  1463. connectDataInfo = &connectDataBuffers->ReceiveDisconnectOptions;
  1464. size = TRUE;
  1465. break;
  1466. default:
  1467. ASSERT(FALSE);
  1468. }
  1469. //
  1470. // Determine the buffer size based on whether we're setting a buffer
  1471. // into which data will be received, in which case the size is
  1472. // in the four bytes of input buffer, or setting a buffer which we're
  1473. // going to send, in which case the size is the length of the input
  1474. // buffer.
  1475. //
  1476. if( size ) {
  1477. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) ) {
  1478. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1479. return STATUS_INVALID_PARAMETER;
  1480. }
  1481. bufferLength = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
  1482. } else {
  1483. bufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  1484. }
  1485. //
  1486. // If there's not currently a buffer of the requested type, or there is
  1487. // such a buffer and it's smaller than the requested size, free it
  1488. // and allocate a new one.
  1489. //
  1490. if( connectDataInfo->Buffer == NULL ||
  1491. connectDataInfo->BufferLength < bufferLength ) {
  1492. if( connectDataInfo->Buffer != NULL ) {
  1493. AFD_FREE_POOL(
  1494. connectDataInfo->Buffer,
  1495. AFD_CONNECT_DATA_POOL_TAG
  1496. );
  1497. }
  1498. connectDataInfo->Buffer = NULL;
  1499. connectDataInfo->BufferLength = 0;
  1500. try {
  1501. connectDataInfo->Buffer = AFD_ALLOCATE_POOL_WITH_QUOTA(
  1502. NonPagedPool,
  1503. bufferLength,
  1504. AFD_CONNECT_DATA_POOL_TAG
  1505. );
  1506. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1507. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1508. return STATUS_INSUFFICIENT_RESOURCES;
  1509. }
  1510. if ( connectDataInfo->Buffer == NULL ) {
  1511. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1512. return STATUS_INSUFFICIENT_RESOURCES;
  1513. }
  1514. }
  1515. //
  1516. // If this wasn't simply a "size" request, copy the data into the buffer.
  1517. //
  1518. if( !size ) {
  1519. RtlCopyMemory(
  1520. connectDataInfo->Buffer,
  1521. Irp->AssociatedIrp.SystemBuffer,
  1522. bufferLength
  1523. );
  1524. }
  1525. connectDataInfo->BufferLength = bufferLength;
  1526. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1527. Irp->IoStatus.Information = 0;
  1528. return STATUS_SUCCESS;
  1529. } // AfdSetConnectData
  1530. NTSTATUS
  1531. AfdSaveReceivedConnectData (
  1532. IN OUT PAFD_CONNECT_DATA_BUFFERS * DataBuffers,
  1533. IN ULONG IoControlCode,
  1534. IN PVOID Buffer,
  1535. IN ULONG BufferLength
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. This helper routine stores the specified *received* connect/disconnect
  1540. data/options on the specified endpoint/connection.
  1541. N.B. This routine MUST be called with AfdSpinLock held!
  1542. N.B. Unlike AfdSetConnectData(), this routine cannot allocate the
  1543. AFD_CONNECT_DATA_BUFFERS structure with quota, as it may be
  1544. called from AfdDisconnectEventHandler() in an unknown thread
  1545. context.
  1546. Arguments:
  1547. DataBuffers -Points to a pointer to the connect data buffers structure.
  1548. If the value pointed to by DataBuffers is NULL, then a new structure
  1549. is allocated, otherwise the existing structure is used.
  1550. IoControlCode - Specifies the type of data to save.
  1551. Buffer - Points to the buffer containing the data.
  1552. BufferLength - The length of Buffer.
  1553. Return Value:
  1554. NTSTATUS - The completion status.
  1555. --*/
  1556. {
  1557. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  1558. PAFD_CONNECT_DATA_INFO connectDataInfo;
  1559. ASSERT( KeGetCurrentIrql() >= DISPATCH_LEVEL );
  1560. //
  1561. // If there's no connect data buffer structure, allocate one now.
  1562. //
  1563. connectDataBuffers = *DataBuffers;
  1564. if( connectDataBuffers == NULL ) {
  1565. connectDataBuffers = AFD_ALLOCATE_POOL(
  1566. NonPagedPool,
  1567. sizeof(*connectDataBuffers),
  1568. AFD_CONNECT_DATA_POOL_TAG
  1569. );
  1570. if( connectDataBuffers == NULL ) {
  1571. return STATUS_INSUFFICIENT_RESOURCES;
  1572. }
  1573. RtlZeroMemory(
  1574. connectDataBuffers,
  1575. sizeof(*connectDataBuffers)
  1576. );
  1577. *DataBuffers = connectDataBuffers;
  1578. }
  1579. //
  1580. // Determine what sort of data we're handling and where it should
  1581. // go.
  1582. //
  1583. switch( IoControlCode ) {
  1584. case IOCTL_AFD_SET_CONNECT_DATA:
  1585. connectDataInfo = &connectDataBuffers->ReceiveConnectData;
  1586. break;
  1587. case IOCTL_AFD_SET_CONNECT_OPTIONS:
  1588. connectDataInfo = &connectDataBuffers->ReceiveConnectOptions;
  1589. break;
  1590. case IOCTL_AFD_SET_DISCONNECT_DATA:
  1591. connectDataInfo = &connectDataBuffers->ReceiveDisconnectData;
  1592. break;
  1593. case IOCTL_AFD_SET_DISCONNECT_OPTIONS:
  1594. connectDataInfo = &connectDataBuffers->ReceiveDisconnectOptions;
  1595. break;
  1596. default:
  1597. ASSERT(FALSE);
  1598. }
  1599. //
  1600. // If there was previously a buffer of the requested type, free it.
  1601. //
  1602. if( connectDataInfo->Buffer != NULL ) {
  1603. AFD_FREE_POOL(
  1604. connectDataInfo->Buffer,
  1605. AFD_CONNECT_DATA_POOL_TAG
  1606. );
  1607. connectDataInfo->Buffer = NULL;
  1608. }
  1609. //
  1610. // Allocate a new buffer for the data and copy in the data we're to
  1611. // send.
  1612. //
  1613. connectDataInfo->Buffer = AFD_ALLOCATE_POOL(
  1614. NonPagedPool,
  1615. BufferLength,
  1616. AFD_CONNECT_DATA_POOL_TAG
  1617. );
  1618. if( connectDataInfo->Buffer == NULL ) {
  1619. return STATUS_INSUFFICIENT_RESOURCES;
  1620. }
  1621. RtlCopyMemory(
  1622. connectDataInfo->Buffer,
  1623. Buffer,
  1624. BufferLength
  1625. );
  1626. connectDataInfo->BufferLength = BufferLength;
  1627. return STATUS_SUCCESS;
  1628. } // AfdSaveReceivedConnectData
  1629. VOID
  1630. AfdFreeConnectDataBuffers (
  1631. IN PAFD_CONNECT_DATA_BUFFERS ConnectDataBuffers
  1632. )
  1633. {
  1634. if ( ConnectDataBuffers->SendConnectData.Buffer != NULL ) {
  1635. AFD_FREE_POOL(
  1636. ConnectDataBuffers->SendConnectData.Buffer,
  1637. AFD_CONNECT_DATA_POOL_TAG
  1638. );
  1639. }
  1640. if ( ConnectDataBuffers->ReceiveConnectData.Buffer != NULL ) {
  1641. AFD_FREE_POOL(
  1642. ConnectDataBuffers->ReceiveConnectData.Buffer,
  1643. AFD_CONNECT_DATA_POOL_TAG
  1644. );
  1645. }
  1646. if ( ConnectDataBuffers->SendConnectOptions.Buffer != NULL ) {
  1647. AFD_FREE_POOL(
  1648. ConnectDataBuffers->SendConnectOptions.Buffer,
  1649. AFD_CONNECT_DATA_POOL_TAG
  1650. );
  1651. }
  1652. if ( ConnectDataBuffers->ReceiveConnectOptions.Buffer != NULL ) {
  1653. AFD_FREE_POOL(
  1654. ConnectDataBuffers->ReceiveConnectOptions.Buffer,
  1655. AFD_CONNECT_DATA_POOL_TAG
  1656. );
  1657. }
  1658. if ( ConnectDataBuffers->SendDisconnectData.Buffer != NULL ) {
  1659. AFD_FREE_POOL(
  1660. ConnectDataBuffers->SendDisconnectData.Buffer,
  1661. AFD_CONNECT_DATA_POOL_TAG
  1662. );
  1663. }
  1664. if ( ConnectDataBuffers->ReceiveDisconnectData.Buffer != NULL ) {
  1665. AFD_FREE_POOL(
  1666. ConnectDataBuffers->ReceiveDisconnectData.Buffer,
  1667. AFD_CONNECT_DATA_POOL_TAG
  1668. );
  1669. }
  1670. if ( ConnectDataBuffers->SendDisconnectOptions.Buffer != NULL ) {
  1671. AFD_FREE_POOL(
  1672. ConnectDataBuffers->SendDisconnectOptions.Buffer,
  1673. AFD_CONNECT_DATA_POOL_TAG
  1674. );
  1675. }
  1676. if ( ConnectDataBuffers->ReceiveDisconnectOptions.Buffer != NULL ) {
  1677. AFD_FREE_POOL(
  1678. ConnectDataBuffers->ReceiveDisconnectOptions.Buffer,
  1679. AFD_CONNECT_DATA_POOL_TAG
  1680. );
  1681. }
  1682. AFD_FREE_POOL(
  1683. ConnectDataBuffers,
  1684. AFD_CONNECT_DATA_POOL_TAG
  1685. );
  1686. return;
  1687. } // AfdFreeConnectDataBuffers
  1688. PAFD_WORK_ITEM
  1689. AfdAllocateWorkItem(
  1690. VOID
  1691. )
  1692. {
  1693. PAFD_WORK_ITEM afdWorkItem;
  1694. afdWorkItem = ExAllocateFromNPagedLookasideList(
  1695. &AfdLookasideLists->WorkQueueList
  1696. );
  1697. ASSERT( afdWorkItem != NULL );
  1698. return afdWorkItem;
  1699. } // AfdAllocateWorkItem
  1700. VOID
  1701. AfdQueueWorkItem (
  1702. IN PWORKER_THREAD_ROUTINE AfdWorkerRoutine,
  1703. IN PAFD_WORK_ITEM AfdWorkItem
  1704. )
  1705. {
  1706. KIRQL oldIrql;
  1707. ASSERT( AfdWorkerRoutine != NULL );
  1708. ASSERT( AfdWorkItem != NULL );
  1709. AfdWorkItem->AfdWorkerRoutine = AfdWorkerRoutine;
  1710. //
  1711. // Insert the work item at the tail of AFD's list of work itrems.
  1712. //
  1713. AfdAcquireSpinLock( &AfdWorkQueueSpinLock, &oldIrql );
  1714. InsertTailList( &AfdWorkQueueListHead, &AfdWorkItem->WorkItemListEntry );
  1715. AfdRecordAfdWorkItemsQueued();
  1716. //
  1717. // If there is no executive worker thread working on AFD work, fire
  1718. // off an executive worker thread to start servicing the list.
  1719. //
  1720. if ( !AfdWorkThreadRunning ) {
  1721. //
  1722. // Remember that the work thread is running and release the
  1723. // lock. Note that we must release the lock before queuing the
  1724. // work because the worker thread may unlock AFD and we can't
  1725. // hold a lock when AFD is unlocked.
  1726. //
  1727. AfdRecordExWorkItemsQueued();
  1728. AfdWorkThreadRunning = TRUE;
  1729. AfdReleaseSpinLock( &AfdWorkQueueSpinLock, oldIrql );
  1730. ExInitializeWorkItem( &AfdWorkQueueItem, AfdDoWork, NULL );
  1731. ExQueueWorkItem( &AfdWorkQueueItem, DelayedWorkQueue );
  1732. } else {
  1733. AfdReleaseSpinLock( &AfdWorkQueueSpinLock, oldIrql );
  1734. }
  1735. return;
  1736. } // AfdQueueWorkItem
  1737. VOID
  1738. AfdFreeWorkItem(
  1739. IN PAFD_WORK_ITEM AfdWorkItem
  1740. )
  1741. {
  1742. ExFreeToNPagedLookasideList(
  1743. &AfdLookasideLists->WorkQueueList,
  1744. AfdWorkItem
  1745. );
  1746. } // AfdFreeWorkItem
  1747. #if DBG
  1748. PVOID
  1749. NTAPI
  1750. AfdAllocateWorkItemPool(
  1751. IN POOL_TYPE PoolType,
  1752. IN ULONG NumberOfBytes,
  1753. IN ULONG Tag
  1754. )
  1755. {
  1756. ASSERT( Tag == AFD_WORK_ITEM_POOL_TAG );
  1757. return AFD_ALLOCATE_POOL(
  1758. PoolType,
  1759. NumberOfBytes,
  1760. Tag
  1761. );
  1762. }
  1763. VOID
  1764. NTAPI
  1765. AfdFreeWorkItemPool(
  1766. IN PVOID Block
  1767. )
  1768. {
  1769. AFD_FREE_POOL(
  1770. Block,
  1771. AFD_WORK_ITEM_POOL_TAG
  1772. );
  1773. }
  1774. #endif
  1775. VOID
  1776. AfdDoWork (
  1777. IN PVOID Context
  1778. )
  1779. {
  1780. PAFD_WORK_ITEM afdWorkItem;
  1781. PLIST_ENTRY listEntry;
  1782. KIRQL oldIrql;
  1783. PWORKER_THREAD_ROUTINE workerRoutine;
  1784. ASSERT( AfdWorkThreadRunning );
  1785. //
  1786. // Empty the queue of AFD work items.
  1787. //
  1788. AfdAcquireSpinLock( &AfdWorkQueueSpinLock, &oldIrql );
  1789. AfdRecordWorkerEnter();
  1790. AfdRecordAfdWorkerThread( PsGetCurrentThread() );
  1791. while ( !IsListEmpty( &AfdWorkQueueListHead ) ) {
  1792. //
  1793. // Take the first item from the queue and find the address
  1794. // of the AFD work item structure.
  1795. //
  1796. listEntry = RemoveHeadList( &AfdWorkQueueListHead );
  1797. afdWorkItem = CONTAINING_RECORD(
  1798. listEntry,
  1799. AFD_WORK_ITEM,
  1800. WorkItemListEntry
  1801. );
  1802. AfdRecordAfdWorkItemsProcessed();
  1803. //
  1804. // Capture the worker thread routine from the item.
  1805. //
  1806. workerRoutine = afdWorkItem->AfdWorkerRoutine;
  1807. //
  1808. // If this work item is going to unlock AFD, then remember that
  1809. // the worker thread is no longer running. This closes the
  1810. // window where AFD gets unloaded at the same time as new work
  1811. // comes in and gets put on the work queue. Note that we
  1812. // must reset this boolean BEFORE releasing the spin lock.
  1813. //
  1814. if( workerRoutine == AfdUnlockDriver ) {
  1815. AfdWorkThreadRunning = FALSE;
  1816. AfdRecordAfdWorkerThread( NULL );
  1817. AfdRecordWorkerLeave();
  1818. }
  1819. //
  1820. // Release the lock and then call the AFD worker routine.
  1821. //
  1822. AfdReleaseSpinLock( &AfdWorkQueueSpinLock, oldIrql );
  1823. workerRoutine( afdWorkItem );
  1824. //
  1825. // If the purpose of this work item was to unload AFD, then
  1826. // we know that there is no more work to do and we CANNOT
  1827. // acquire a spin lock. Quit servicing the list and return.
  1828. //
  1829. if( workerRoutine == AfdUnlockDriver ) {
  1830. return;
  1831. }
  1832. //
  1833. // Reacquire the spin lock and continue servicing the list.
  1834. //
  1835. AfdAcquireSpinLock( &AfdWorkQueueSpinLock, &oldIrql );
  1836. }
  1837. //
  1838. // Remember that we're no longer servicing the list and release the
  1839. // spin lock.
  1840. //
  1841. AfdRecordAfdWorkerThread( NULL );
  1842. AfdRecordWorkerLeave();
  1843. AfdWorkThreadRunning = FALSE;
  1844. AfdReleaseSpinLock( &AfdWorkQueueSpinLock, oldIrql );
  1845. } // AfdDoWork
  1846. #if DBG
  1847. typedef struct _AFD_OUTSTANDING_IRP {
  1848. LIST_ENTRY OutstandingIrpListEntry;
  1849. PIRP OutstandingIrp;
  1850. PCHAR FileName;
  1851. ULONG LineNumber;
  1852. } AFD_OUTSTANDING_IRP, *PAFD_OUTSTANDING_IRP;
  1853. NTSTATUS
  1854. AfdIoCallDriverDebug (
  1855. IN PAFD_ENDPOINT Endpoint,
  1856. IN PDEVICE_OBJECT DeviceObject,
  1857. IN PIRP Irp,
  1858. IN PCHAR FileName,
  1859. IN ULONG LineNumber
  1860. )
  1861. {
  1862. PAFD_OUTSTANDING_IRP outstandingIrp;
  1863. KIRQL oldIrql;
  1864. //
  1865. // Get an outstanding IRP structure to hold the IRP.
  1866. //
  1867. outstandingIrp = AFD_ALLOCATE_POOL(
  1868. NonPagedPool,
  1869. sizeof(AFD_OUTSTANDING_IRP),
  1870. AFD_DEBUG_POOL_TAG
  1871. );
  1872. if ( outstandingIrp == NULL ) {
  1873. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1874. IoSetNextIrpStackLocation( Irp );
  1875. IoCompleteRequest( Irp, AfdPriorityBoost );
  1876. return STATUS_INSUFFICIENT_RESOURCES;
  1877. }
  1878. //
  1879. // Initialize the structure and place it on the endpoint's list of
  1880. // outstanding IRPs.
  1881. //
  1882. outstandingIrp->OutstandingIrp = Irp;
  1883. outstandingIrp->FileName = FileName;
  1884. outstandingIrp->LineNumber = LineNumber;
  1885. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  1886. InsertTailList(
  1887. &Endpoint->OutstandingIrpListHead,
  1888. &outstandingIrp->OutstandingIrpListEntry
  1889. );
  1890. Endpoint->OutstandingIrpCount++;
  1891. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1892. //
  1893. // Pass the IRP to the TDI provider.
  1894. //
  1895. return IoCallDriver( DeviceObject, Irp );
  1896. } // AfdIoCallDriverDebug
  1897. VOID
  1898. AfdCompleteOutstandingIrpDebug (
  1899. IN PAFD_ENDPOINT Endpoint,
  1900. IN PIRP Irp
  1901. )
  1902. {
  1903. PAFD_OUTSTANDING_IRP outstandingIrp;
  1904. KIRQL oldIrql;
  1905. PLIST_ENTRY listEntry;
  1906. //
  1907. // First find the IRP on the endpoint's list of outstanding IRPs.
  1908. //
  1909. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  1910. for ( listEntry = Endpoint->OutstandingIrpListHead.Flink;
  1911. listEntry != &Endpoint->OutstandingIrpListHead;
  1912. listEntry = listEntry->Flink ) {
  1913. outstandingIrp = CONTAINING_RECORD(
  1914. listEntry,
  1915. AFD_OUTSTANDING_IRP,
  1916. OutstandingIrpListEntry
  1917. );
  1918. if ( outstandingIrp->OutstandingIrp == Irp ) {
  1919. RemoveEntryList( listEntry );
  1920. ASSERT( Endpoint->OutstandingIrpCount != 0 );
  1921. Endpoint->OutstandingIrpCount--;
  1922. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1923. AFD_FREE_POOL(
  1924. outstandingIrp,
  1925. AFD_DEBUG_POOL_TAG
  1926. );
  1927. return;
  1928. }
  1929. }
  1930. //
  1931. // The corresponding outstanding IRP structure was not found. This
  1932. // should never happen unless an allocate for an outstanding IRP
  1933. // structure failed above.
  1934. //
  1935. KdPrint(( "AfdCompleteOutstandingIrp: Irp %lx not found on endpoint %lx\n",
  1936. Irp, Endpoint ));
  1937. ASSERT( Endpoint->OutstandingIrpCount != 0 );
  1938. Endpoint->OutstandingIrpCount--;
  1939. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  1940. return;
  1941. } // AfdCompleteOutstandingIrpDebug
  1942. #else
  1943. NTSTATUS
  1944. AfdIoCallDriverFree (
  1945. IN PAFD_ENDPOINT Endpoint,
  1946. IN PDEVICE_OBJECT DeviceObject,
  1947. IN PIRP Irp
  1948. )
  1949. {
  1950. //
  1951. // Increment the count of IRPs outstanding on the endpoint. This
  1952. // allows the cleanup code to abort the VC if there is outstanding
  1953. // IO when a cleanup occurs.
  1954. //
  1955. InterlockedIncrement(
  1956. &Endpoint->OutstandingIrpCount
  1957. );
  1958. //
  1959. // Pass the IRP to the TDI provider.
  1960. //
  1961. return IoCallDriver( DeviceObject, Irp );
  1962. } // AfdIoCallDriverFree
  1963. VOID
  1964. AfdCompleteOutstandingIrpFree (
  1965. IN PAFD_ENDPOINT Endpoint,
  1966. IN PIRP Irp
  1967. )
  1968. {
  1969. //
  1970. // Decrement the count of IRPs on the endpoint.
  1971. //
  1972. InterlockedDecrement(
  1973. &Endpoint->OutstandingIrpCount
  1974. );
  1975. return;
  1976. } // AfdCompleteOutstandingIrpFree
  1977. #endif
  1978. #if DBG || REFERENCE_DEBUG
  1979. VOID
  1980. AfdInitializeDebugData (
  1981. VOID
  1982. )
  1983. {
  1984. //
  1985. // Empty for now.
  1986. //
  1987. } // AfdInitializeDebugData
  1988. #endif
  1989. #if DBG
  1990. #undef ExAllocatePool
  1991. #undef ExFreePool
  1992. ULONG AfdTotalAllocations = 0;
  1993. ULONG AfdTotalFrees = 0;
  1994. LARGE_INTEGER AfdTotalBytesAllocated;
  1995. LARGE_INTEGER AfdTotalBytesFreed;
  1996. //
  1997. // N.B. This structure MUST be quadword aligned!
  1998. //
  1999. typedef struct _AFD_POOL_HEADER {
  2000. PCHAR FileName;
  2001. ULONG LineNumber;
  2002. ULONG Size;
  2003. ULONG InUse;
  2004. #if !FREE_POOL_WITH_TAG_SUPPORTED
  2005. LONG Tag;
  2006. LONG Dummy; // for proper alignment
  2007. #endif
  2008. } AFD_POOL_HEADER, *PAFD_POOL_HEADER;
  2009. PVOID
  2010. AfdAllocatePool (
  2011. IN POOL_TYPE PoolType,
  2012. IN ULONG NumberOfBytes,
  2013. IN ULONG Tag,
  2014. IN PCHAR FileName,
  2015. IN ULONG LineNumber,
  2016. IN BOOLEAN WithQuota
  2017. )
  2018. {
  2019. PAFD_POOL_HEADER header;
  2020. KIRQL oldIrql;
  2021. ASSERT( PoolType == NonPagedPool ||
  2022. PoolType == NonPagedPoolMustSucceed ||
  2023. PoolType == PagedPool );
  2024. if ( WithQuota ) {
  2025. try {
  2026. header = ExAllocatePoolWithQuotaTag(
  2027. PoolType,
  2028. NumberOfBytes + sizeof(*header),
  2029. Tag
  2030. );
  2031. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2032. return NULL;
  2033. }
  2034. } else {
  2035. header = ExAllocatePoolWithTag(
  2036. PoolType,
  2037. NumberOfBytes + sizeof(*header),
  2038. Tag
  2039. );
  2040. }
  2041. if ( header == NULL ) {
  2042. return NULL;
  2043. }
  2044. header->FileName = FileName;
  2045. header->LineNumber = LineNumber;
  2046. header->Size = NumberOfBytes;
  2047. header->InUse = 1;
  2048. #if !FREE_POOL_WITH_TAG_SUPPORTED
  2049. header->Tag = (LONG)Tag;
  2050. #endif
  2051. InterlockedIncrement(
  2052. &AfdTotalAllocations
  2053. );
  2054. ExInterlockedAddLargeStatistic(
  2055. &AfdTotalBytesAllocated,
  2056. header->Size
  2057. );
  2058. return (PVOID)(header + 1);
  2059. } // AfdAllocatePool
  2060. VOID
  2061. AfdFreePool (
  2062. IN PVOID Pointer,
  2063. IN ULONG Tag
  2064. )
  2065. {
  2066. KIRQL oldIrql;
  2067. PAFD_POOL_HEADER header = (PAFD_POOL_HEADER)Pointer - 1;
  2068. InterlockedIncrement(
  2069. &AfdTotalFrees
  2070. );
  2071. ExInterlockedAddLargeStatistic(
  2072. &AfdTotalBytesFreed,
  2073. header->Size
  2074. );
  2075. header->InUse = 0;
  2076. #if !FREE_POOL_WITH_TAG_SUPPORTED
  2077. ASSERT( InterlockedExchange( &header->Tag, 0 ) == (LONG)Tag );
  2078. #endif
  2079. MyFreePoolWithTag(
  2080. (PVOID)header,
  2081. Tag
  2082. );
  2083. } // AfdFreePool
  2084. #ifdef AFDDBG_QUOTA
  2085. typedef struct {
  2086. union {
  2087. ULONG Bytes;
  2088. struct {
  2089. UCHAR Reserved[3];
  2090. UCHAR Sign;
  2091. } ;
  2092. } ;
  2093. UCHAR Location[12];
  2094. PVOID Block;
  2095. PVOID Process;
  2096. PVOID Reserved2[2];
  2097. } QUOTA_HISTORY, *PQUOTA_HISTORY;
  2098. #define QUOTA_HISTORY_LENGTH 512
  2099. QUOTA_HISTORY AfdQuotaHistory[QUOTA_HISTORY_LENGTH];
  2100. LONG AfdQuotaHistoryIndex = 0;
  2101. VOID
  2102. AfdRecordQuotaHistory(
  2103. IN PEPROCESS Process,
  2104. IN LONG Bytes,
  2105. IN PSZ Type,
  2106. IN PVOID Block
  2107. )
  2108. {
  2109. KIRQL oldIrql;
  2110. LONG index;
  2111. PQUOTA_HISTORY history;
  2112. index = InterlockedIncrement( &AfdQuotaHistoryIndex );
  2113. index &= QUOTA_HISTORY_LENGTH - 1;
  2114. history = &AfdQuotaHistory[index];
  2115. history->Bytes = Bytes;
  2116. history->Sign = Bytes < 0 ? '-' : '+';
  2117. RtlCopyMemory( history->Location, Type, 12 );
  2118. history->Block = Block;
  2119. history->Process = Process;
  2120. } // AfdRecordQuotaHistory
  2121. #endif
  2122. #endif
  2123. PMDL
  2124. AfdAdvanceMdlChain(
  2125. IN PMDL Mdl,
  2126. IN ULONG Offset
  2127. )
  2128. /*++
  2129. Routine Description:
  2130. Accepts a pointer to an existing MDL chain and offsets that chain
  2131. by a specified number of bytes. This may involve the creation
  2132. of a partial MDL for the first entry in the new chain.
  2133. Arguments:
  2134. Mdl - Pointer to the MDL chain to advance.
  2135. Offset - The number of bytes to offset the chain.
  2136. Return Value:
  2137. NTSTATUS -- Indicates the status of the request.
  2138. --*/
  2139. {
  2140. PMDL partialMdl;
  2141. PVOID virtualAddress;
  2142. //
  2143. // Sanity check.
  2144. //
  2145. ASSERT( Mdl != NULL );
  2146. ASSERT( Offset > 0 );
  2147. //
  2148. // Scan past any fully completed MDLs.
  2149. //
  2150. while ( Offset > MmGetMdlByteCount( Mdl ) ) {
  2151. Offset -= MmGetMdlByteCount( Mdl );
  2152. ASSERT( Mdl->Next != NULL );
  2153. Mdl = Mdl->Next;
  2154. }
  2155. //
  2156. // Tautology of the day: Offset will either be zero (meaning that
  2157. // we've advanced to a clean boundary between MDLs) or non-zero
  2158. // (meaning we need to now build a partial MDL).
  2159. //
  2160. if ( Offset > 0 ) {
  2161. //
  2162. // Compute the virtual address for the new MDL.
  2163. //
  2164. virtualAddress = (PVOID)((PUCHAR)MmGetMdlVirtualAddress( Mdl ) + Offset);
  2165. //
  2166. // Allocate the partial MDL.
  2167. //
  2168. partialMdl = IoAllocateMdl(
  2169. virtualAddress,
  2170. MmGetMdlByteCount( Mdl ) - Offset,
  2171. FALSE, // SecondaryBuffer
  2172. FALSE, // ChargeQuota
  2173. NULL // Irp
  2174. );
  2175. if ( partialMdl != NULL ) {
  2176. //
  2177. // Map part of the existing MDL into the parital MDL.
  2178. //
  2179. IoBuildPartialMdl(
  2180. Mdl,
  2181. partialMdl,
  2182. virtualAddress,
  2183. MmGetMdlByteCount( Mdl ) - Offset
  2184. );
  2185. }
  2186. //
  2187. // Return the parital MDL.
  2188. //
  2189. Mdl = partialMdl;
  2190. }
  2191. return Mdl;
  2192. } // AfdAdvanceMdlChain
  2193. NTSTATUS
  2194. AfdAllocateMdlChain(
  2195. IN PIRP Irp,
  2196. IN LPWSABUF BufferArray,
  2197. IN ULONG BufferCount,
  2198. IN LOCK_OPERATION Operation,
  2199. OUT PULONG TotalByteCount
  2200. )
  2201. /*++
  2202. Routine Description:
  2203. Allocates a MDL chain describing the WSABUF array and attaches
  2204. the chain to the specified IRP.
  2205. Arguments:
  2206. Irp - The IRP that will receive the MDL chain.
  2207. BufferArray - Points to an array of WSABUF structures describing
  2208. the user's buffers.
  2209. BufferCount - Contains the number of WSABUF structures in the
  2210. array.
  2211. Operation - Specifies the type of operation being performed (either
  2212. IoReadAccess or IoWriteAccess).
  2213. TotalByteCount - Will receive the total number of BYTEs described
  2214. by the WSABUF array.
  2215. Return Value:
  2216. NTSTATUS -- Indicates the status of the request.
  2217. --*/
  2218. {
  2219. NTSTATUS status;
  2220. PMDL currentMdl;
  2221. PMDL * chainTarget;
  2222. KPROCESSOR_MODE previousMode;
  2223. ULONG totalLength;
  2224. PVOID bufferPointer;
  2225. ULONG bufferLength;
  2226. //
  2227. // Sanity check.
  2228. //
  2229. ASSERT( Irp != NULL );
  2230. ASSERT( Irp->MdlAddress == NULL );
  2231. ASSERT( BufferArray != NULL );
  2232. ASSERT( BufferCount > 0 );
  2233. ASSERT( ( Operation == IoReadAccess ) || ( Operation == IoWriteAccess ) );
  2234. ASSERT( TotalByteCount != NULL );
  2235. //
  2236. // Get the previous processor mode.
  2237. //
  2238. previousMode = Irp->RequestorMode;
  2239. //
  2240. // Get into a known state.
  2241. //
  2242. status = STATUS_SUCCESS;
  2243. currentMdl = NULL;
  2244. chainTarget = &Irp->MdlAddress;
  2245. totalLength = 0;
  2246. //
  2247. // Walk the array of WSABUF structures, creating the MDLs and
  2248. // probing & locking the pages.
  2249. //
  2250. try {
  2251. if( previousMode != KernelMode ) {
  2252. //
  2253. // Probe the WSABUF array.
  2254. //
  2255. ProbeForRead(
  2256. BufferArray, // Address
  2257. BufferCount * sizeof(WSABUF), // Length
  2258. sizeof(ULONG) // Alignment
  2259. );
  2260. }
  2261. //
  2262. // Scan the array.
  2263. //
  2264. do {
  2265. bufferPointer = BufferArray->buf;
  2266. bufferLength = BufferArray->len;
  2267. if( bufferPointer != NULL &&
  2268. bufferLength > 0 ) {
  2269. //
  2270. // Update the total byte counter.
  2271. //
  2272. totalLength += bufferLength;
  2273. //
  2274. // Create a new MDL.
  2275. //
  2276. currentMdl = IoAllocateMdl(
  2277. bufferPointer, // VirtualAddress
  2278. bufferLength, // Length
  2279. FALSE, // SecondaryBuffer
  2280. TRUE, // ChargeQuota
  2281. NULL // Irp
  2282. );
  2283. if( currentMdl != NULL ) {
  2284. //
  2285. // Lock the pages. This will raise an exception
  2286. // if the operation fails.
  2287. //
  2288. MmProbeAndLockPages(
  2289. currentMdl, // MemoryDescriptorList
  2290. previousMode, // AccessMode
  2291. Operation // Operation
  2292. );
  2293. //
  2294. // Chain the MDL onto the IRP. In theory, we could
  2295. // do this by passing the IRP into IoAllocateMdl(),
  2296. // but IoAllocateMdl() does a linear scan on the MDL
  2297. // chain to find the last one in the chain.
  2298. //
  2299. // We can do much better.
  2300. //
  2301. *chainTarget = currentMdl;
  2302. chainTarget = &currentMdl->Next;
  2303. //
  2304. // Advance to the next WSABUF structure.
  2305. //
  2306. BufferArray++;
  2307. } else {
  2308. //
  2309. // Cannot allocate new MDL, return appropriate error.
  2310. //
  2311. status = STATUS_INSUFFICIENT_RESOURCES;
  2312. break;
  2313. }
  2314. }
  2315. } while( --BufferCount );
  2316. //
  2317. // Ensure the MDL chain is NULL terminated.
  2318. //
  2319. ASSERT( *chainTarget == NULL );
  2320. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2321. //
  2322. // Bad news. Snag the exception code.
  2323. //
  2324. status = GetExceptionCode();
  2325. //
  2326. // currentMdl will only be non-NULL at this point if an MDL
  2327. // has been created, but MmProbeAndLockPages() raised an
  2328. // exception. If this is true, then free the MDL.
  2329. //
  2330. if( currentMdl != NULL ) {
  2331. IoFreeMdl( currentMdl );
  2332. }
  2333. }
  2334. //
  2335. // Return the total buffer count.
  2336. //
  2337. *TotalByteCount = totalLength;
  2338. return status;
  2339. } // AfdAllocateMdlChain
  2340. VOID
  2341. AfdDestroyMdlChain (
  2342. IN PIRP Irp
  2343. )
  2344. /*++
  2345. Routine Description:
  2346. Unlocks & frees the MDLs in the MDL chain attached to the given IRP.
  2347. Arguments:
  2348. Irp - The IRP that owns the MDL chain to destroy.
  2349. Return Value:
  2350. None.
  2351. --*/
  2352. {
  2353. PMDL mdl;
  2354. PMDL nextMdl;
  2355. mdl = Irp->MdlAddress;
  2356. Irp->MdlAddress = NULL;
  2357. while( mdl != NULL ) {
  2358. nextMdl = mdl->Next;
  2359. MmUnlockPages( mdl );
  2360. IoFreeMdl( mdl );
  2361. mdl = nextMdl;
  2362. }
  2363. } // AfdDestroyMdlChain
  2364. ULONG
  2365. AfdCalcBufferArrayByteLengthRead(
  2366. IN LPWSABUF BufferArray,
  2367. IN ULONG BufferCount
  2368. )
  2369. /*++
  2370. Routine Description:
  2371. Calculates the total size (in bytes) of the buffers described by the
  2372. specified WSABUF array and probes those buffers for read access.
  2373. Arguments:
  2374. BufferArray - Points to an array of WSABUF structures.
  2375. BufferCount - The number of entries in BufferArray.
  2376. Return Value:
  2377. ULONG - The total size (in bytes) of the buffers described by the
  2378. WSABUF array. Will raise an exception & return -1 if the total
  2379. size is obviously too large.
  2380. --*/
  2381. {
  2382. LARGE_INTEGER totalLength;
  2383. KPROCESSOR_MODE previousMode;
  2384. PAGED_CODE( );
  2385. //
  2386. // Sanity check.
  2387. //
  2388. ASSERT( BufferArray != NULL );
  2389. ASSERT( BufferCount > 0 );
  2390. previousMode = ExGetPreviousMode();
  2391. if( previousMode != KernelMode ) {
  2392. //
  2393. // Probe the WSABUF array.
  2394. //
  2395. ProbeForRead(
  2396. BufferArray, // Address
  2397. BufferCount * sizeof(WSABUF), // Length
  2398. sizeof(ULONG) // Alignment
  2399. );
  2400. }
  2401. //
  2402. // Scan the array & sum the lengths.
  2403. //
  2404. totalLength.QuadPart = 0;
  2405. while( BufferCount-- ) {
  2406. if( previousMode != KernelMode ) {
  2407. ProbeForRead(
  2408. BufferArray->buf, // Address
  2409. BufferArray->len, // Length
  2410. sizeof(UCHAR) // Alignment
  2411. );
  2412. }
  2413. totalLength.QuadPart += (LONGLONG)BufferArray->len;
  2414. BufferArray++;
  2415. }
  2416. if( totalLength.HighPart == 0 &&
  2417. ( totalLength.LowPart & 0x80000000 ) == 0 ) {
  2418. return totalLength.LowPart;
  2419. }
  2420. ExRaiseAccessViolation();
  2421. return (ULONG)-1L;
  2422. } // AfdCalcBufferArrayByteLengthRead
  2423. ULONG
  2424. AfdCalcBufferArrayByteLengthWrite(
  2425. IN LPWSABUF BufferArray,
  2426. IN ULONG BufferCount
  2427. )
  2428. /*++
  2429. Routine Description:
  2430. Calculates the total size (in bytes) of the buffers described by the
  2431. specified WSABUF array and probes those buffers for write access.
  2432. Arguments:
  2433. BufferArray - Points to an array of WSABUF structures.
  2434. BufferCount - The number of entries in BufferArray.
  2435. Return Value:
  2436. ULONG - The total size (in bytes) of the buffers described by the
  2437. WSABUF array. Will raise an exception & return -1 if the total
  2438. size is obviously too large.
  2439. --*/
  2440. {
  2441. LARGE_INTEGER totalLength;
  2442. KPROCESSOR_MODE previousMode;
  2443. PAGED_CODE( );
  2444. //
  2445. // Sanity check.
  2446. //
  2447. ASSERT( BufferArray != NULL );
  2448. ASSERT( BufferCount > 0 );
  2449. previousMode = ExGetPreviousMode();
  2450. if( previousMode != KernelMode ) {
  2451. //
  2452. // Probe the WSABUF array.
  2453. //
  2454. ProbeForRead(
  2455. BufferArray, // Address
  2456. BufferCount * sizeof(WSABUF), // Length
  2457. sizeof(ULONG) // Alignment
  2458. );
  2459. }
  2460. //
  2461. // Scan the array & sum the lengths.
  2462. //
  2463. totalLength.QuadPart = 0;
  2464. while( BufferCount-- ) {
  2465. if( previousMode != KernelMode ) {
  2466. ProbeForWrite(
  2467. BufferArray->buf, // Address
  2468. BufferArray->len, // Length
  2469. sizeof(UCHAR) // Alignment
  2470. );
  2471. }
  2472. totalLength.QuadPart += (LONGLONG)BufferArray->len;
  2473. BufferArray++;
  2474. }
  2475. if( totalLength.HighPart == 0 &&
  2476. ( totalLength.LowPart & 0x80000000 ) == 0 ) {
  2477. return totalLength.LowPart;
  2478. }
  2479. ExRaiseAccessViolation();
  2480. return (ULONG)-1L;
  2481. } // AfdCalcBufferArrayByteLengthWrite
  2482. ULONG
  2483. AfdCopyBufferArrayToBuffer(
  2484. IN PVOID Destination,
  2485. IN ULONG DestinationLength,
  2486. IN LPWSABUF BufferArray,
  2487. IN ULONG BufferCount
  2488. )
  2489. /*++
  2490. Routine Description:
  2491. Copies data from a WSABUF array to a linear buffer.
  2492. Arguments:
  2493. Destination - Points to the linear destination of the data.
  2494. DestinationLength - The length of Destination.
  2495. BufferArray - Points to an array of WSABUF structures describing the
  2496. source for the copy.
  2497. BufferCount - The number of entries in BufferArray.
  2498. Return Value:
  2499. ULONG - The number of bytes copied.
  2500. --*/
  2501. {
  2502. PVOID destinationStart;
  2503. ULONG bytesToCopy;
  2504. PAGED_CODE( );
  2505. //
  2506. // Sanity check.
  2507. //
  2508. ASSERT( Destination != NULL );
  2509. ASSERT( BufferArray != NULL );
  2510. ASSERT( BufferCount > 0 );
  2511. //
  2512. // Remember this so we can calc number of bytes copied.
  2513. //
  2514. destinationStart = Destination;
  2515. //
  2516. // Scan the array & copy to the linear buffer.
  2517. //
  2518. while( BufferCount-- && DestinationLength > 0 ) {
  2519. bytesToCopy = min( DestinationLength, BufferArray->len );
  2520. RtlCopyMemory(
  2521. Destination,
  2522. BufferArray->buf,
  2523. bytesToCopy
  2524. );
  2525. Destination = (PCHAR)Destination + bytesToCopy;
  2526. DestinationLength -= bytesToCopy;
  2527. BufferArray++;
  2528. }
  2529. //
  2530. // Return number of bytes copied.
  2531. //
  2532. return (PCHAR)Destination - (PCHAR)destinationStart;
  2533. } // AfdCopyBufferArrayToBuffer
  2534. ULONG
  2535. AfdCopyBufferToBufferArray(
  2536. IN LPWSABUF BufferArray,
  2537. IN ULONG Offset,
  2538. IN ULONG BufferCount,
  2539. IN PVOID Source,
  2540. IN ULONG SourceLength
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. Copies data from a linear buffer to a WSABUF array.
  2545. Arguments:
  2546. BufferArray - Points to an array of WSABUF structures describing the
  2547. destination for the copy.
  2548. Offset - An offset within the buffer array at which the data should
  2549. be copied.
  2550. BufferCount - The number of entries in BufferArray.
  2551. Source - Points to the linear source of the data.
  2552. SourceLength - The length of Source.
  2553. Return Value:
  2554. ULONG - The number of bytes copied.
  2555. --*/
  2556. {
  2557. PVOID sourceStart;
  2558. ULONG bytesToCopy;
  2559. PAGED_CODE( );
  2560. //
  2561. // Sanity check.
  2562. //
  2563. ASSERT( BufferArray != NULL );
  2564. ASSERT( BufferCount > 0 );
  2565. ASSERT( Source != NULL );
  2566. //
  2567. // Remember this so we can return the number of bytes copied.
  2568. //
  2569. sourceStart = Source;
  2570. //
  2571. // Handle the offset if one was specified.
  2572. //
  2573. if( Offset > 0 ) {
  2574. //
  2575. // Skip whole entries if necessary.
  2576. //
  2577. while( BufferCount > 0 && Offset >= BufferArray->len ) {
  2578. Offset -= BufferArray->len;
  2579. BufferArray++;
  2580. BufferCount--;
  2581. }
  2582. //
  2583. // If there's a fragmented portion remaining, and we still
  2584. // have buffers left, then copy the fragment here to keep
  2585. // the loop below fast.
  2586. //
  2587. if( Offset > 0 && BufferCount > 0 ) {
  2588. ASSERT( Offset < BufferArray->len );
  2589. bytesToCopy = min( SourceLength, BufferArray->len - Offset );
  2590. RtlCopyMemory(
  2591. BufferArray->buf + Offset,
  2592. Source,
  2593. bytesToCopy
  2594. );
  2595. Source = (PCHAR)Source + bytesToCopy;
  2596. SourceLength -= bytesToCopy;
  2597. BufferArray++;
  2598. BufferCount--;
  2599. }
  2600. }
  2601. //
  2602. // Scan the array & copy from the linear buffer.
  2603. //
  2604. while( BufferCount-- && SourceLength > 0 ) {
  2605. bytesToCopy = min( SourceLength, BufferArray->len );
  2606. RtlCopyMemory(
  2607. BufferArray->buf,
  2608. Source,
  2609. bytesToCopy
  2610. );
  2611. Source = (PCHAR)Source + bytesToCopy;
  2612. SourceLength -= bytesToCopy;
  2613. BufferArray++;
  2614. }
  2615. //
  2616. // Return number of bytes copied.
  2617. //
  2618. return (PCHAR)Source - (PCHAR)sourceStart;
  2619. } // AfdCopyBufferToBufferArray
  2620. #ifdef NT351
  2621. NTSTATUS
  2622. AfdReferenceEventObjectByHandle(
  2623. IN HANDLE Handle,
  2624. IN KPROCESSOR_MODE AccessMode,
  2625. OUT PVOID *Object
  2626. )
  2627. /*++
  2628. Routine Description:
  2629. References an event object by handle, returning a pointer to the
  2630. object.
  2631. Arguments:
  2632. Handle - The event handle to reference.
  2633. AccessMode - The requestor mode (user or kernel).
  2634. Object - Receives a pointer to the event object.
  2635. Return Value:
  2636. NTSTATUS - Completion status.
  2637. --*/
  2638. {
  2639. NTSTATUS status;
  2640. PKEVENT eventObject;
  2641. PAGED_CODE( );
  2642. //
  2643. // Reference the event object, but pass a NULL ObjectType descriptor
  2644. // to ObReferenceObjectByHandle(). We must do this because the NT 3.51
  2645. // kernel does not export the ExEventObjectType descriptor.
  2646. //
  2647. status = ObReferenceObjectByHandle(
  2648. Handle, // Handle
  2649. 0, // DesiredAccess
  2650. NULL, // ObjectType
  2651. AccessMode, // AccessMode
  2652. Object, // Object,
  2653. NULL // HandleInformation
  2654. );
  2655. if( NT_SUCCESS(status) ) {
  2656. eventObject = (PKEVENT)*Object;
  2657. //
  2658. // Since we had to pass in a NULL object type descriptor, OB
  2659. // couldn't validate the object type for us. In an attempt to
  2660. // ensure we don't just blindly use the resulting object, we'll
  2661. // make a few sanity checks here.
  2662. //
  2663. if( ( eventObject->Header.Type == NotificationEvent ||
  2664. eventObject->Header.Type == SynchronizationEvent ) &&
  2665. eventObject->Header.Size == sizeof(*eventObject ) &&
  2666. eventObject->Header.Inserted == 0 &&
  2667. (ULONG)eventObject->Header.SignalState <= 1 ) {
  2668. return STATUS_SUCCESS;
  2669. }
  2670. //
  2671. // Object type mismatch.
  2672. //
  2673. ObDereferenceObject( eventObject );
  2674. return STATUS_OBJECT_TYPE_MISMATCH;
  2675. }
  2676. //
  2677. // ObReferenceObjectByHandle() failure.
  2678. //
  2679. return status;
  2680. } // AfdReferenceEventObjectByHandle
  2681. NTSTATUS
  2682. AfdQueueUserApc (
  2683. IN PIRP Irp,
  2684. IN PIO_STACK_LOCATION IrpSp
  2685. )
  2686. /*++
  2687. Routine Description:
  2688. Queues a user-mode APC.
  2689. Arguments:
  2690. Irp - Pointer to I/O request packet.
  2691. IrpSp - pointer to the IO stack location to use for this request.
  2692. Return Value:
  2693. NTSTATUS -- Indicates whether the APC was successfully queued.
  2694. --*/
  2695. {
  2696. PAFD_QUEUE_APC_INFO apcInfo;
  2697. PAFD_APC afdApc;
  2698. PETHREAD threadObject;
  2699. NTSTATUS status;
  2700. PAGED_CODE( );
  2701. //
  2702. // Set up local pointers.
  2703. //
  2704. apcInfo = Irp->AssociatedIrp.SystemBuffer;
  2705. //
  2706. // Validate the parameters.
  2707. //
  2708. if( apcInfo == NULL ||
  2709. IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*apcInfo) ||
  2710. apcInfo->Thread == NULL ||
  2711. apcInfo->ApcRoutine == NULL ) {
  2712. return STATUS_INVALID_PARAMETER;
  2713. }
  2714. //
  2715. // Reference the target thread object.
  2716. //
  2717. status = ObReferenceObjectByHandle(
  2718. apcInfo->Thread, // Handle
  2719. 0, // DesiredAccess
  2720. *(POBJECT_TYPE *)PsThreadType, // ObjectType
  2721. Irp->RequestorMode, // AccessMode
  2722. (PVOID *)&threadObject, // Object
  2723. NULL // HandleInformation
  2724. );
  2725. if ( !NT_SUCCESS(status) ) {
  2726. return status;
  2727. }
  2728. //
  2729. // Create the APC object.
  2730. //
  2731. afdApc = AFD_ALLOCATE_POOL(
  2732. NonPagedPool,
  2733. sizeof(*afdApc),
  2734. AFD_APC_POOL_TAG
  2735. );
  2736. if ( afdApc == NULL ) {
  2737. ObDereferenceObject(threadObject);
  2738. return STATUS_INSUFFICIENT_RESOURCES;
  2739. }
  2740. //
  2741. // Initialize the APC object.
  2742. //
  2743. KeInitializeApc(
  2744. &afdApc->Apc, // Apc
  2745. &threadObject->Tcb, // Thread
  2746. CurrentApcEnvironment, // Environment
  2747. AfdSpecialApc, // KernelRoutine
  2748. AfdSpecialApcRundown, // RundownRoutine
  2749. (PKNORMAL_ROUTINE)apcInfo->ApcRoutine, // NormalRoutine
  2750. Irp->RequestorMode, // ProcessorMode
  2751. apcInfo->ApcContext // NormalContext
  2752. );
  2753. //
  2754. // Insert the APC into the thread's queue.
  2755. //
  2756. KeInsertQueueApc(
  2757. &afdApc->Apc, // Apc
  2758. apcInfo->SystemArgument1, // SystemArgument1
  2759. apcInfo->SystemArgument2, // SystemArgument2
  2760. 0 // Increment
  2761. );
  2762. //
  2763. // Dereference the target thread. Note that the AFD_APC structure
  2764. // will be freed in either AfdSpecialApc (if the APC was successfully
  2765. // delivered to the target thread) or AfdSpecialApcRundown (if the
  2766. // target thread was destroyed before the APC could be delivered).
  2767. //
  2768. ObDereferenceObject(threadObject);
  2769. Irp->IoStatus.Information = 0;
  2770. return STATUS_SUCCESS;
  2771. } // AfdQueueUserApc
  2772. VOID
  2773. AfdSpecialApc (
  2774. struct _KAPC *Apc,
  2775. PKNORMAL_ROUTINE *NormalRoutine,
  2776. PVOID *NormalContext,
  2777. PVOID *SystemArgument1,
  2778. PVOID *SystemArgument2
  2779. )
  2780. /*++
  2781. Routine Description:
  2782. This is the kernel apc routine.
  2783. The only real work needed here is to free the AFD_APC structure
  2784. allocated in AfdQueueUserApc().
  2785. Arguments:
  2786. Apc - pointer to apc object
  2787. NormalRoutine - Will be called when we return.
  2788. NormalContext - will be 1st argument to normal routine.
  2789. SystemArgument1 - Uninterpreted.
  2790. SystemArgument2 - Uninterpreted.
  2791. Return Value:
  2792. NONE.
  2793. --*/
  2794. {
  2795. PAFD_APC afdApc;
  2796. PAGED_CODE();
  2797. ASSERT( Apc != NULL );
  2798. //
  2799. // Grab a pointer to the APC's containing AFD_APC structure,
  2800. // then free it.
  2801. //
  2802. afdApc = CONTAINING_RECORD( Apc, AFD_APC, Apc );
  2803. AFD_FREE_POOL(
  2804. afdApc,
  2805. AFD_APC_POOL_TAG
  2806. );
  2807. } // AfdSpecialApc
  2808. VOID
  2809. AfdSpecialApcRundown (
  2810. struct _KAPC *Apc
  2811. )
  2812. /*++
  2813. Routine Description:
  2814. This routine is called to clear away apcs in the apc queue
  2815. of a thread that has been terminated.
  2816. The only real work needed here is to free the AFD_APC structure
  2817. allocated in AfdQueueUserApc().
  2818. Arguments:
  2819. Apc - pointer to apc object
  2820. Return Value:
  2821. NONE.
  2822. --*/
  2823. {
  2824. PAFD_APC afdApc;
  2825. PAGED_CODE();
  2826. ASSERT( Apc != NULL );
  2827. //
  2828. // Grab a pointer to the APC's containing AFD_APC structure,
  2829. // then free it.
  2830. //
  2831. afdApc = CONTAINING_RECORD( Apc, AFD_APC, Apc );
  2832. AFD_FREE_POOL(
  2833. afdApc,
  2834. AFD_APC_POOL_TAG
  2835. );
  2836. } // AfdSpecialApcRundown
  2837. #endif // NT351
  2838. #if DBG
  2839. VOID
  2840. AfdAssert(
  2841. IN PVOID FailedAssertion,
  2842. IN PVOID FileName,
  2843. IN ULONG LineNumber,
  2844. IN PCHAR Message OPTIONAL
  2845. )
  2846. {
  2847. if( AfdUsePrivateAssert ) {
  2848. DbgPrint(
  2849. "\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n",
  2850. Message
  2851. ? Message
  2852. : "",
  2853. FailedAssertion,
  2854. FileName,
  2855. LineNumber
  2856. );
  2857. DbgBreakPoint();
  2858. } else {
  2859. RtlAssert(
  2860. FailedAssertion,
  2861. FileName,
  2862. LineNumber,
  2863. Message
  2864. );
  2865. }
  2866. } // AfdAssert
  2867. #endif // DBG
  2868. NTSTATUS
  2869. AfdSetQos(
  2870. IN PIRP Irp,
  2871. IN PIO_STACK_LOCATION IrpSp
  2872. )
  2873. /*++
  2874. Routine Description:
  2875. This routine sets the QOS for the given endpoint. Note that, since
  2876. we don't really (yet) support QOS, we just ignore the incoming
  2877. data and issue a AFD_POLL_QOS or AFD_POLL_GROUP_QOS event as
  2878. appropriate.
  2879. Arguments:
  2880. Irp - Pointer to I/O request packet.
  2881. IrpSp - pointer to the IO stack location to use for this request.
  2882. Return Value:
  2883. NTSTATUS -- Indicates whether the request was successfully queued.
  2884. --*/
  2885. {
  2886. PAFD_ENDPOINT endpoint;
  2887. PAFD_QOS_INFO qosInfo;
  2888. PAGED_CODE();
  2889. //
  2890. // Set up local pointers.
  2891. //
  2892. endpoint = IrpSp->FileObject->FsContext;
  2893. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2894. qosInfo = Irp->AssociatedIrp.SystemBuffer;
  2895. //
  2896. // Make sure that the input buffer is large enough.
  2897. //
  2898. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  2899. sizeof(*qosInfo) ) {
  2900. return STATUS_BUFFER_TOO_SMALL;
  2901. }
  2902. //
  2903. // If the incoming data doesn't match the default QOS,
  2904. // indicate the appropriate event.
  2905. //
  2906. if( !RtlEqualMemory(
  2907. &qosInfo->Qos,
  2908. &AfdDefaultQos,
  2909. sizeof(QOS)
  2910. ) ) {
  2911. AfdIndicatePollEvent(
  2912. endpoint,
  2913. qosInfo->GroupQos
  2914. ? AFD_POLL_GROUP_QOS_BIT
  2915. : AFD_POLL_QOS_BIT,
  2916. STATUS_SUCCESS
  2917. );
  2918. }
  2919. //
  2920. // Complete the IRP.
  2921. //
  2922. Irp->IoStatus.Information = 0;
  2923. return STATUS_SUCCESS;
  2924. } // AfdSetQos
  2925. NTSTATUS
  2926. AfdGetQos(
  2927. IN PIRP Irp,
  2928. IN PIO_STACK_LOCATION IrpSp
  2929. )
  2930. /*++
  2931. Routine Description:
  2932. This routine gets the QOS for the given endpoint.
  2933. Arguments:
  2934. Irp - Pointer to I/O request packet.
  2935. IrpSp - pointer to the IO stack location to use for this request.
  2936. Return Value:
  2937. NTSTATUS -- Indicates whether the request was successfully queued.
  2938. --*/
  2939. {
  2940. PAFD_ENDPOINT endpoint;
  2941. PAFD_QOS_INFO qosInfo;
  2942. PAGED_CODE();
  2943. //
  2944. // Set up local pointers.
  2945. //
  2946. endpoint = IrpSp->FileObject->FsContext;
  2947. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2948. qosInfo = Irp->AssociatedIrp.SystemBuffer;
  2949. //
  2950. // Make sure that the output buffer is large enough.
  2951. //
  2952. if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2953. sizeof(*qosInfo) ) {
  2954. return STATUS_BUFFER_TOO_SMALL;
  2955. }
  2956. //
  2957. // Just return the default data.
  2958. //
  2959. RtlCopyMemory(
  2960. &qosInfo->Qos,
  2961. &AfdDefaultQos,
  2962. sizeof(QOS)
  2963. );
  2964. //
  2965. // Complete the IRP.
  2966. //
  2967. Irp->IoStatus.Information = sizeof(*qosInfo);
  2968. return STATUS_SUCCESS;
  2969. } // AfdGetQos
  2970. NTSTATUS
  2971. AfdNoOperation(
  2972. IN PIRP Irp,
  2973. IN PIO_STACK_LOCATION IrpSp
  2974. )
  2975. /*++
  2976. Routine Description:
  2977. This routine does nothing but complete the IRP.
  2978. Arguments:
  2979. Irp - Pointer to I/O request packet.
  2980. IrpSp - pointer to the IO stack location to use for this request.
  2981. Return Value:
  2982. NTSTATUS -- Indicates whether the request was successfully queued.
  2983. --*/
  2984. {
  2985. PAFD_ENDPOINT endpoint;
  2986. PAGED_CODE();
  2987. //
  2988. // Set up local pointers.
  2989. //
  2990. endpoint = IrpSp->FileObject->FsContext;
  2991. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2992. //
  2993. // Complete the IRP.
  2994. //
  2995. Irp->IoStatus.Information = 0;
  2996. return STATUS_SUCCESS;
  2997. } // AfdNoOperation
  2998. NTSTATUS
  2999. AfdValidateGroup(
  3000. IN PIRP Irp,
  3001. IN PIO_STACK_LOCATION IrpSp
  3002. )
  3003. /*++
  3004. Routine Description:
  3005. This routine examines a group ID. If the ID is for a "constrained"
  3006. group, then all endpoints are scanned to validate the given address
  3007. is consistent with the constrained group.
  3008. Arguments:
  3009. Irp - Pointer to I/O request packet.
  3010. IrpSp - pointer to the IO stack location to use for this request.
  3011. Return Value:
  3012. NTSTATUS -- Indicates whether the request was successfully queued.
  3013. --*/
  3014. {
  3015. PAFD_ENDPOINT endpoint;
  3016. PAFD_ENDPOINT compareEndpoint;
  3017. PAFD_CONNECTION connection;
  3018. PLIST_ENTRY listEntry;
  3019. PAFD_VALIDATE_GROUP_INFO validateInfo;
  3020. AFD_GROUP_TYPE groupType;
  3021. PTRANSPORT_ADDRESS requestAddress;
  3022. ULONG requestAddressLength;
  3023. KIRQL oldIrql;
  3024. BOOLEAN result;
  3025. LONG groupId;
  3026. PAGED_CODE();
  3027. //
  3028. // Set up local pointers.
  3029. //
  3030. endpoint = IrpSp->FileObject->FsContext;
  3031. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  3032. validateInfo = Irp->AssociatedIrp.SystemBuffer;
  3033. //
  3034. // Make sure that the input buffer is large enough.
  3035. //
  3036. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3037. sizeof(*validateInfo) ) {
  3038. return STATUS_BUFFER_TOO_SMALL;
  3039. }
  3040. if( validateInfo->RemoteAddress.TAAddressCount != 1 ) {
  3041. return STATUS_INVALID_PARAMETER;
  3042. }
  3043. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3044. ( sizeof(*validateInfo) -
  3045. sizeof(TRANSPORT_ADDRESS) +
  3046. validateInfo->RemoteAddress.Address[0].AddressLength ) ) {
  3047. return STATUS_BUFFER_TOO_SMALL;
  3048. }
  3049. //
  3050. // Start by referencing the group so it doesn't go away unexpectedly.
  3051. // This will also validate the group ID, and give us the group type.
  3052. //
  3053. groupId = validateInfo->GroupID;
  3054. if( !AfdReferenceGroup( groupId, &groupType ) ) {
  3055. return STATUS_INVALID_PARAMETER;
  3056. }
  3057. //
  3058. // If it's not a constrained group ID, we can just complete the IRP
  3059. // successfully right now.
  3060. //
  3061. if( groupType != GroupTypeConstrained ) {
  3062. AfdDereferenceGroup( validateInfo->GroupID );
  3063. Irp->IoStatus.Information = 0;
  3064. return STATUS_SUCCESS;
  3065. }
  3066. //
  3067. // Calculate the size of the incoming TDI address.
  3068. //
  3069. requestAddress = &validateInfo->RemoteAddress;
  3070. requestAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength -
  3071. sizeof(AFD_VALIDATE_GROUP_INFO) +
  3072. sizeof(TRANSPORT_ADDRESS);
  3073. //
  3074. // OK, it's a constrained group. Scan the list of constrained endpoints,
  3075. // find those that are either datagram endpoints or have associated
  3076. // connections, and validate the remote addresses.
  3077. //
  3078. result = TRUE;
  3079. ExAcquireResourceShared( AfdResource, TRUE );
  3080. for( listEntry = AfdConstrainedEndpointListHead.Flink ;
  3081. listEntry != &AfdConstrainedEndpointListHead ;
  3082. listEntry = listEntry->Flink ) {
  3083. compareEndpoint = CONTAINING_RECORD(
  3084. listEntry,
  3085. AFD_ENDPOINT,
  3086. ConstrainedEndpointListEntry
  3087. );
  3088. ASSERT( IS_AFD_ENDPOINT_TYPE( compareEndpoint ) );
  3089. ASSERT( compareEndpoint->GroupType == GroupTypeConstrained );
  3090. //
  3091. // Skip this endpoint if the group IDs don't match.
  3092. //
  3093. if( groupId != compareEndpoint->GroupID ) {
  3094. continue;
  3095. }
  3096. //
  3097. // If this is a datagram endpoint, check it's remote address.
  3098. //
  3099. if( IS_DGRAM_ENDPOINT( compareEndpoint ) ) {
  3100. AfdAcquireSpinLock( &compareEndpoint->SpinLock, &oldIrql );
  3101. if( compareEndpoint->Common.Datagram.RemoteAddress != NULL &&
  3102. compareEndpoint->Common.Datagram.RemoteAddressLength ==
  3103. requestAddressLength ) {
  3104. result = AfdCompareAddresses(
  3105. compareEndpoint->Common.Datagram.RemoteAddress,
  3106. compareEndpoint->Common.Datagram.RemoteAddressLength,
  3107. requestAddress,
  3108. requestAddressLength
  3109. );
  3110. }
  3111. AfdReleaseSpinLock( &compareEndpoint->SpinLock, oldIrql );
  3112. if( !result ) {
  3113. break;
  3114. }
  3115. } else {
  3116. //
  3117. // Not a datagram. If it's a connected endpoint, still has
  3118. // a connection object, and that object has a remote address,
  3119. // then compare the addresses.
  3120. //
  3121. AfdAcquireSpinLock( &compareEndpoint->SpinLock, &oldIrql );
  3122. connection = AFD_CONNECTION_FROM_ENDPOINT( compareEndpoint );
  3123. if( compareEndpoint->State == AfdEndpointStateConnected &&
  3124. connection != NULL ) {
  3125. REFERENCE_CONNECTION( connection );
  3126. AfdReleaseSpinLock( &compareEndpoint->SpinLock, oldIrql );
  3127. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  3128. if( connection->RemoteAddress != NULL &&
  3129. connection->RemoteAddressLength == requestAddressLength ) {
  3130. result = AfdCompareAddresses(
  3131. connection->RemoteAddress,
  3132. connection->RemoteAddressLength,
  3133. requestAddress,
  3134. requestAddressLength
  3135. );
  3136. }
  3137. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  3138. DEREFERENCE_CONNECTION( connection );
  3139. if( !result ) {
  3140. break;
  3141. }
  3142. } else {
  3143. AfdReleaseSpinLock( &compareEndpoint->SpinLock, oldIrql );
  3144. }
  3145. }
  3146. }
  3147. ExReleaseResource( AfdResource );
  3148. AfdDereferenceGroup( validateInfo->GroupID );
  3149. if( !result ) {
  3150. return STATUS_INVALID_PARAMETER;
  3151. }
  3152. //
  3153. // Success!
  3154. //
  3155. Irp->IoStatus.Information = 0;
  3156. return STATUS_SUCCESS;
  3157. } // AfdValidateGroup
  3158. BOOLEAN
  3159. AfdCompareAddresses(
  3160. IN PTRANSPORT_ADDRESS Address1,
  3161. IN ULONG Address1Length,
  3162. IN PTRANSPORT_ADDRESS Address2,
  3163. IN ULONG Address2Length
  3164. )
  3165. /*++
  3166. Routine Description:
  3167. This routine compares two addresses in a special way to support
  3168. constrained socket groups. This routine will return TRUE if the
  3169. two addresses represent the same "interface". By "interface", I
  3170. mean something like an IP address or an IPX address. Note that for
  3171. some address types (such as IP) certain portions of the address
  3172. should be ignored (such as the port).
  3173. I really hate hard-coded knowledge of "select" address types, but
  3174. there's no easy way around it. Ideally, this should be the protocol
  3175. driver's responsibility. We could really use a standard "compare
  3176. these addresses" IOCTL in TDI.
  3177. Arguments:
  3178. Address1 - The first address.
  3179. Address1Length - The length of Address1.
  3180. Address2 - The second address.
  3181. Address2Length - The length of Address2.
  3182. Return Value:
  3183. BOOLEAN - TRUE if the addresses reference the same interface, FALSE
  3184. otherwise.
  3185. --*/
  3186. {
  3187. USHORT addressType;
  3188. addressType = Address1->Address[0].AddressType;
  3189. if( addressType != Address2->Address[0].AddressType ) {
  3190. //
  3191. // If they're not the same address type, they can't be the
  3192. // same address...
  3193. //
  3194. return FALSE;
  3195. }
  3196. //
  3197. // Special case a few addresses.
  3198. //
  3199. switch( addressType ) {
  3200. case TDI_ADDRESS_TYPE_IP : {
  3201. TDI_ADDRESS_IP UNALIGNED * ip1;
  3202. TDI_ADDRESS_IP UNALIGNED * ip2;
  3203. ip1 = (PVOID)&Address1->Address[0].Address[0];
  3204. ip2 = (PVOID)&Address2->Address[0].Address[0];
  3205. //
  3206. // IP addresses. Compare the address portion (ignoring
  3207. // the port).
  3208. //
  3209. if( ip1->in_addr == ip2->in_addr ) {
  3210. return TRUE;
  3211. }
  3212. }
  3213. return FALSE;
  3214. case TDI_ADDRESS_TYPE_IPX : {
  3215. TDI_ADDRESS_IPX UNALIGNED * ipx1;
  3216. TDI_ADDRESS_IPX UNALIGNED * ipx2;
  3217. ipx1 = (PVOID)&Address1->Address[0].Address[0];
  3218. ipx2 = (PVOID)&Address2->Address[0].Address[0];
  3219. //
  3220. // IPX addresses. Compare the network and node addresses.
  3221. //
  3222. if( ipx1->NetworkAddress == ipx2->NetworkAddress &&
  3223. RtlEqualMemory(
  3224. ipx1->NodeAddress,
  3225. ipx2->NodeAddress,
  3226. sizeof(ipx1->NodeAddress)
  3227. ) ) {
  3228. return TRUE;
  3229. }
  3230. }
  3231. return FALSE;
  3232. case TDI_ADDRESS_TYPE_APPLETALK : {
  3233. TDI_ADDRESS_APPLETALK UNALIGNED * atalk1;
  3234. TDI_ADDRESS_APPLETALK UNALIGNED * atalk2;
  3235. atalk1 = (PVOID)&Address1->Address[0].Address[0];
  3236. atalk2 = (PVOID)&Address2->Address[0].Address[0];
  3237. //
  3238. // APPLETALK address. Compare the network and node
  3239. // addresses.
  3240. //
  3241. if( atalk1->Network == atalk2->Network &&
  3242. atalk1->Node == atalk2->Node ) {
  3243. return TRUE;
  3244. }
  3245. }
  3246. return FALSE;
  3247. case TDI_ADDRESS_TYPE_VNS : {
  3248. TDI_ADDRESS_VNS UNALIGNED * vns1;
  3249. TDI_ADDRESS_VNS UNALIGNED * vns2;
  3250. vns1 = (PVOID)&Address1->Address[0].Address[0];
  3251. vns2 = (PVOID)&Address2->Address[0].Address[0];
  3252. //
  3253. // VNS addresses. Compare the network and subnet addresses.
  3254. //
  3255. if( RtlEqualMemory(
  3256. vns1->net_address,
  3257. vns2->net_address,
  3258. sizeof(vns1->net_address)
  3259. ) &&
  3260. RtlEqualMemory(
  3261. vns1->subnet_addr,
  3262. vns2->subnet_addr,
  3263. sizeof(vns1->subnet_addr)
  3264. ) ) {
  3265. return TRUE;
  3266. }
  3267. }
  3268. return FALSE;
  3269. default :
  3270. //
  3271. // Unknown address type. Do a simple memory compare.
  3272. //
  3273. return (BOOLEAN)RtlEqualMemory(
  3274. Address1,
  3275. Address2,
  3276. Address2Length
  3277. );
  3278. }
  3279. } // AfdCompareAddresses
  3280. PAFD_CONNECTION
  3281. AfdFindReturnedConnection(
  3282. IN PAFD_ENDPOINT Endpoint,
  3283. IN ULONG Sequence
  3284. )
  3285. /*++
  3286. Routine Description:
  3287. Scans the endpoints queue of returned connections looking for one
  3288. with the specified sequence number.
  3289. Arguments:
  3290. Endpoint - A pointer to the endpoint from which to get a connection.
  3291. Sequence - The sequence the connection must match. This is actually
  3292. a pointer to the connection.
  3293. Return Value:
  3294. AFD_CONNECTION - A pointer to an AFD connection block if successful,
  3295. NULL if not.
  3296. --*/
  3297. {
  3298. PAFD_CONNECTION connection;
  3299. PLIST_ENTRY listEntry;
  3300. ASSERT( Endpoint != NULL );
  3301. ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
  3302. //
  3303. // Walk the endpoint's list of returned connections until we reach
  3304. // the end or until we find one with a matching sequence.
  3305. //
  3306. for( listEntry = Endpoint->Common.VcListening.ReturnedConnectionListHead.Flink;
  3307. listEntry != &Endpoint->Common.VcListening.ReturnedConnectionListHead;
  3308. listEntry = listEntry->Flink ) {
  3309. connection = CONTAINING_RECORD(
  3310. listEntry,
  3311. AFD_CONNECTION,
  3312. ListEntry
  3313. );
  3314. if( Sequence == (ULONG)connection ) {
  3315. return connection;
  3316. }
  3317. }
  3318. return NULL;
  3319. } // AfdFindReturnedConnection
  3320. NTSTATUS
  3321. AfdGetUnacceptedConnectData (
  3322. IN PIRP Irp,
  3323. IN PIO_STACK_LOCATION IrpSp
  3324. )
  3325. {
  3326. PAFD_ENDPOINT endpoint;
  3327. PAFD_CONNECTION connection;
  3328. PAFD_CONNECT_DATA_BUFFERS connectDataBuffers;
  3329. PAFD_UNACCEPTED_CONNECT_DATA_INFO connectInfo;
  3330. KIRQL oldIrql;
  3331. ULONG dataLength;
  3332. //
  3333. // Set up local pointers.
  3334. //
  3335. endpoint = IrpSp->FileObject->FsContext;
  3336. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  3337. connectInfo = Irp->AssociatedIrp.SystemBuffer;
  3338. //
  3339. // Validate the request.
  3340. //
  3341. if( endpoint->Type != AfdBlockTypeVcListening ||
  3342. IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3343. sizeof(*connectInfo) ) {
  3344. return STATUS_INVALID_PARAMETER;
  3345. }
  3346. if( connectInfo->LengthOnly &&
  3347. IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3348. sizeof(*connectInfo) ) {
  3349. return STATUS_INVALID_PARAMETER;
  3350. }
  3351. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  3352. //
  3353. // Find the specified connection.
  3354. //
  3355. connection = AfdFindReturnedConnection(
  3356. endpoint,
  3357. connectInfo->Sequence
  3358. );
  3359. if( connection == NULL ) {
  3360. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  3361. return STATUS_INVALID_PARAMETER;
  3362. }
  3363. //
  3364. // Determine the length of any received connect data.
  3365. //
  3366. dataLength = 0;
  3367. connectDataBuffers = connection->ConnectDataBuffers;
  3368. if( connectDataBuffers != NULL &&
  3369. connectDataBuffers->ReceiveConnectData.Buffer != NULL ) {
  3370. dataLength = connectDataBuffers->ReceiveConnectData.BufferLength;
  3371. }
  3372. //
  3373. // If the caller is just interested in the data length, return it.
  3374. //
  3375. if( connectInfo->LengthOnly ) {
  3376. connectInfo->ConnectDataLength = dataLength;
  3377. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  3378. Irp->IoStatus.Information = sizeof(*connectInfo);
  3379. return STATUS_SUCCESS;
  3380. }
  3381. //
  3382. // If there is no connect data, complete the IRP with no bytes.
  3383. //
  3384. if( dataLength == 0 ) {
  3385. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  3386. Irp->IoStatus.Information = 0;
  3387. return STATUS_SUCCESS;
  3388. }
  3389. //
  3390. // If the output buffer is too small, fail.
  3391. //
  3392. if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < dataLength ) {
  3393. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  3394. return STATUS_BUFFER_TOO_SMALL;
  3395. }
  3396. //
  3397. // Copy over the buffer and return the number of bytes copied.
  3398. //
  3399. RtlCopyMemory(
  3400. Irp->AssociatedIrp.SystemBuffer,
  3401. connectDataBuffers->ReceiveConnectData.Buffer,
  3402. dataLength
  3403. );
  3404. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  3405. Irp->IoStatus.Information = dataLength;
  3406. return STATUS_SUCCESS;
  3407. } // AfdGetUnacceptedConnectData