Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7136 lines
220 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. tpackets.c
  5. Abstract:
  6. This module contains support for fast kernel-level file transmission
  7. over a socket handle.
  8. Author:
  9. Vadim Eydelman (VadimE) January 1999
  10. Revision History:
  11. --*/
  12. #include "afdp.h"
  13. //
  14. // Macros to make TransmitPackets code readble
  15. //
  16. #define AfdTPacketsInfo DeviceIoControl
  17. #define AfdTPacketsFlags IoControlCode
  18. #if DBG
  19. PIRP Irp;
  20. C_ASSERT (sizeof (AFD_TPACKETS_IRP_CTX)<=sizeof (Irp->Tail.Overlay.DriverContext));
  21. #endif
  22. #if DBG
  23. ULONG
  24. __inline
  25. AFD_SET_TP_FLAGS (
  26. PIRP TpIrp,
  27. ULONG Flags
  28. )
  29. {
  30. PAFD_TPACKETS_IRP_CTX ctx = AFD_GET_TPIC(TpIrp);
  31. ASSERT ((ctx->StateFlags & Flags)==0);
  32. return InterlockedExchangeAdd ((PLONG)&(ctx)->StateFlags, Flags);
  33. }
  34. ULONG
  35. __inline
  36. AFD_CLEAR_TP_FLAGS (
  37. PIRP TpIrp,
  38. ULONG Flags
  39. )
  40. {
  41. PAFD_TPACKETS_IRP_CTX ctx = AFD_GET_TPIC(TpIrp);
  42. ASSERT ((ctx->StateFlags & Flags)==Flags);
  43. return InterlockedExchangeAdd ((PLONG)&(ctx)->StateFlags, 0-Flags);
  44. }
  45. #else
  46. #define AFD_SET_TP_FLAGS(_i,_f) \
  47. InterlockedExchangeAdd ((PLONG)&AFD_GET_TPIC(_i)->StateFlags, _f)
  48. #define AFD_CLEAR_TP_FLAGS(_i,_f) \
  49. InterlockedExchangeAdd ((PLONG)&AFD_GET_TPIC(_i)->StateFlags, 0-(_f))
  50. #endif
  51. //
  52. // Reference/dereference macros for transmit info structure.
  53. // We keep transmit IRP pending and all the elements of
  54. // the structure till last reference to it is gone.
  55. // Note, that reference can be added only if structure
  56. // already has non-0 reference count.
  57. //
  58. #if REFERENCE_DEBUG
  59. VOID
  60. AfdReferenceTPackets (
  61. IN PIRP Irp,
  62. IN LONG LocationId,
  63. IN ULONG Param
  64. );
  65. LONG
  66. AfdDereferenceTPackets (
  67. IN PIRP Irp,
  68. IN LONG LocationId,
  69. IN ULONG Param
  70. );
  71. VOID
  72. AfdUpdateTPacketsTrack (
  73. IN PIRP Irp,
  74. IN LONG LocationId,
  75. IN ULONG Param
  76. );
  77. #define REFERENCE_TPACKETS(_i) { \
  78. static LONG _arl; \
  79. AfdReferenceTPackets(_i,AFD_GET_ARL(__FILE__"(%d)+"),__LINE__); \
  80. }
  81. #define DEREFERENCE_TPACKETS(_i) { \
  82. static LONG _arl; \
  83. if (AfdDereferenceTPackets(_i,AFD_GET_ARL(__FILE__"(%d)-"),__LINE__)==0) {\
  84. AfdCompleteTPackets(_i); \
  85. };\
  86. }
  87. #define DEREFERENCE_TPACKETS_S(_i) { \
  88. static LONG _arl; \
  89. if (AfdDereferenceTPackets(_i,AFD_GET_ARL(__FILE__"(%d)-"),__LINE__)==0) {\
  90. AfdStartTPacketsWorker(AfdCompleteTPackets,_i); \
  91. } \
  92. }
  93. #define UPDATE_TPACKETS(_i) { \
  94. static LONG _arl; \
  95. AfdUpdateTPacketsTrack((_i),AFD_GET_ARL(__FILE__"(%d)="),__LINE__);\
  96. }
  97. #define UPDATE_TPACKETS2(_i,_s,_p) { \
  98. static LONG _arl; \
  99. AfdUpdateTPacketsTrack((_i),AFD_GET_ARL(_s"="),_p); \
  100. }
  101. #else // REFERENCE_DEBUG
  102. #define REFERENCE_TPACKETS(_i) \
  103. InterlockedIncrement ((PLONG)&AFD_GET_TPIC(_i)->ReferenceCount)
  104. #define DEREFERENCE_TPACKETS(_i) \
  105. if (InterlockedDecrement((PLONG)&AFD_GET_TPIC(_i)->ReferenceCount)==0) {\
  106. AfdCompleteTPackets(_i); \
  107. }
  108. #define DEREFERENCE_TPACKETS_S(_i) { \
  109. if (InterlockedDecrement((PLONG)&AFD_GET_TPIC(_i)->ReferenceCount)==0) {\
  110. AfdStartTPacketsWorker(AfdCompleteTPackets, _i); \
  111. } \
  112. }
  113. #define UPDATE_TPACKETS(_i)
  114. #define UPDATE_TPACKETS2(_i,_s,_p)
  115. #endif // REFERENCE_DEBUG
  116. #if DBG
  117. //
  118. // Doesn't seem like we have a file system that does not
  119. // support cache. So this is here for debugging purposes.
  120. //
  121. ULONG AfdUseCache=TRUE;
  122. #define AFD_USE_CACHE(file) \
  123. (AfdUseCache&&(((file)->Flags&FO_CACHE_SUPPORTED)!=0))
  124. #else // DBG
  125. #define AFD_USE_CACHE(file) (((file)->Flags & FO_CACHE_SUPPORTED)!=0)
  126. #endif // DBG
  127. VOID
  128. AfdTPacketsWorker (
  129. PVOID Context
  130. );
  131. VOID
  132. AfdPerformSuperDisconnect (
  133. PIRP TpIrp
  134. );
  135. NTSTATUS
  136. AfdBuildPacketChain (
  137. PIRP TpIrp,
  138. PAFD_BUFFER_HEADER *Pd
  139. );
  140. BOOLEAN
  141. AfdCleanupPacketChain (
  142. PIRP TpIrp,
  143. BOOLEAN BelowDispatch
  144. );
  145. NTSTATUS
  146. AfdTPacketsSend (
  147. PIRP TpIrp,
  148. USHORT SendIrp
  149. );
  150. NTSTATUS
  151. AfdRestartTPacketsSend (
  152. IN PDEVICE_OBJECT DeviceObject,
  153. IN PIRP Irp,
  154. IN PVOID Context
  155. );
  156. NTSTATUS
  157. AfdRestartTPDetachedSend (
  158. IN PDEVICE_OBJECT DeviceObject,
  159. IN PIRP Irp,
  160. IN PVOID Context
  161. );
  162. USHORT
  163. AfdTPacketsFindSendIrp (
  164. PIRP TpIrp
  165. );
  166. NTSTATUS
  167. AfdTPacketsMdlRead (
  168. PIRP TpIrp,
  169. PAFD_BUFFER_HEADER Pd
  170. );
  171. NTSTATUS
  172. AfdRestartTPacketsMdlRead (
  173. IN PDEVICE_OBJECT DeviceObject,
  174. IN PIRP Irp,
  175. IN PVOID Context
  176. );
  177. NTSTATUS
  178. AfdMdlReadComplete (
  179. PFILE_OBJECT FileObject,
  180. PMDL FileMdl,
  181. PLARGE_INTEGER FileOffset
  182. );
  183. NTSTATUS
  184. AfdRestartMdlReadComplete (
  185. IN PDEVICE_OBJECT DeviceObject,
  186. IN PIRP Irp,
  187. IN PVOID Context
  188. );
  189. VOID
  190. AfdLRMdlReadComplete (
  191. PAFD_BUFFER_HEADER Pd
  192. );
  193. BOOLEAN
  194. AfdLRProcessFileMdlList (
  195. PAFD_LR_LIST_ITEM Item
  196. );
  197. NTSTATUS
  198. AfdTPacketsBufferRead (
  199. PIRP TpIrp,
  200. PAFD_BUFFER_HEADER Pd
  201. );
  202. NTSTATUS
  203. AfdRestartTPacketsBufferRead (
  204. IN PDEVICE_OBJECT DeviceObject,
  205. IN PIRP Irp,
  206. IN PVOID Context
  207. );
  208. BOOLEAN
  209. AfdTPacketsContinueAfterRead (
  210. PIRP TpIrp
  211. );
  212. VOID
  213. AfdCompleteTPackets (
  214. PVOID Context
  215. );
  216. VOID
  217. AfdAbortTPackets (
  218. PIRP TpIrp,
  219. NTSTATUS Status
  220. );
  221. VOID
  222. AfdCancelTPackets (
  223. IN PDEVICE_OBJECT DeviceObject,
  224. IN PIRP Irp
  225. );
  226. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  227. BOOLEAN
  228. AfdTPacketsEnableSendAndDisconnect (
  229. PIRP TpIrp
  230. );
  231. #endif // TDI_SERVICE_SEND_AND_DISCONNECT
  232. BOOLEAN
  233. AfdQueueTransmit (
  234. PIRP Irp
  235. );
  236. VOID
  237. AfdStartNextQueuedTransmit(
  238. VOID
  239. );
  240. VOID
  241. AfdStartTPacketsWorker (
  242. PWORKER_THREAD_ROUTINE WorkerRoutine,
  243. PIRP TpIrp
  244. );
  245. VOID
  246. AfdTPacketsApcKernelRoutine (
  247. IN struct _KAPC *Apc,
  248. IN OUT PKNORMAL_ROUTINE *NormalRoutine,
  249. IN OUT PVOID *NormalContext,
  250. IN OUT PVOID *SystemArgument1,
  251. IN OUT PVOID *SystemArgument2
  252. );
  253. VOID
  254. AfdTPacketsApcRundownRoutine (
  255. IN struct _KAPC *Apc
  256. );
  257. BOOLEAN
  258. AfdEnqueueTPacketsIrp (
  259. PAFD_ENDPOINT Endpoint,
  260. PIRP TpIrp
  261. );
  262. VOID
  263. AfdStartNextTPacketsIrp (
  264. PAFD_ENDPOINT Endpoint,
  265. PIRP TpIrp
  266. );
  267. BOOLEAN
  268. AfdGetTPacketsReference (
  269. PIRP Irp
  270. );
  271. PAFD_TPACKETS_INFO_INTERNAL
  272. AfdGetTpInfo (
  273. ULONG ElementCount
  274. );
  275. VOID
  276. AfdReturnTpInfo (
  277. PAFD_TPACKETS_INFO_INTERNAL TpInfo
  278. );
  279. #ifdef _WIN64
  280. NTSTATUS
  281. AfdTransmitPackets32 (
  282. IN PIRP Irp,
  283. IN PIO_STACK_LOCATION IrpSp,
  284. OUT PAFD_TPACKETS_INFO_INTERNAL *TpInfo
  285. );
  286. #endif //_WIN64
  287. #ifdef ALLOC_PRAGMA
  288. #pragma alloc_text( PAGE, AfdTransmitPackets )
  289. #ifdef _WIN64
  290. #pragma alloc_text( PAGE, AfdTransmitPackets32 )
  291. #endif //_WIN64
  292. #pragma alloc_text( PAGE, AfdTPacketsWorker )
  293. #pragma alloc_text( PAGE, AfdPerformSuperDisconnect )
  294. #pragma alloc_text( PAGE, AfdBuildPacketChain )
  295. #pragma alloc_text( PAGEAFD, AfdCleanupPacketChain )
  296. #pragma alloc_text( PAGEAFD, AfdTPacketsSend )
  297. #pragma alloc_text( PAGEAFD, AfdRestartTPacketsSend )
  298. #pragma alloc_text( PAGEAFD, AfdRestartTPDetachedSend )
  299. #pragma alloc_text( PAGEAFD, AfdTPacketsFindSendIrp)
  300. #pragma alloc_text( PAGE, AfdTPacketsMdlRead )
  301. #pragma alloc_text( PAGEAFD, AfdRestartTPacketsMdlRead )
  302. #pragma alloc_text( PAGE, AfdMdlReadComplete )
  303. #pragma alloc_text( PAGEAFD, AfdRestartMdlReadComplete )
  304. #pragma alloc_text( PAGE, AfdLRMdlReadComplete )
  305. #pragma alloc_text( PAGE, AfdLRProcessFileMdlList )
  306. #pragma alloc_text( PAGE, AfdTPacketsBufferRead )
  307. #pragma alloc_text( PAGEAFD, AfdRestartTPacketsBufferRead )
  308. #pragma alloc_text( PAGEAFD, AfdTPacketsContinueAfterRead )
  309. #pragma alloc_text( PAGEAFD, AfdCompleteTPackets )
  310. #pragma alloc_text( PAGEAFD, AfdAbortTPackets )
  311. #pragma alloc_text( PAGEAFD, AfdCancelTPackets )
  312. #pragma alloc_text( PAGEAFD, AfdCompleteClosePendedTPackets )
  313. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  314. #pragma alloc_text( PAGEAFD, AfdTPacketsEnableSendAndDisconnect )
  315. #endif
  316. #pragma alloc_text( PAGEAFD, AfdQueueTransmit )
  317. #pragma alloc_text( PAGEAFD, AfdStartNextQueuedTransmit )
  318. #pragma alloc_text( PAGEAFD, AfdStartTPacketsWorker )
  319. #pragma alloc_text( PAGE, AfdTPacketsApcKernelRoutine )
  320. #pragma alloc_text( PAGE, AfdTPacketsApcRundownRoutine )
  321. #pragma alloc_text( PAGEAFD, AfdEnqueueTPacketsIrp )
  322. #pragma alloc_text( PAGEAFD, AfdStartNextTPacketsIrp )
  323. #pragma alloc_text( PAGEAFD, AfdGetTPacketsReference )
  324. #if REFERENCE_DEBUG
  325. #pragma alloc_text( PAGEAFD, AfdReferenceTPackets )
  326. #pragma alloc_text( PAGEAFD, AfdDereferenceTPackets )
  327. #pragma alloc_text( PAGEAFD, AfdUpdateTPacketsTrack )
  328. #endif
  329. #pragma alloc_text( PAGE, AfdGetTpInfo )
  330. #pragma alloc_text( PAGEAFD, AfdReturnTpInfo )
  331. #pragma alloc_text( INIT, AfdComputeTpInfoSize )
  332. #pragma alloc_text( PAGEAFD, AfdAllocateTpInfo )
  333. #pragma alloc_text( PAGEAFD, AfdFreeTpInfo )
  334. #endif
  335. NTSTATUS
  336. FASTCALL
  337. AfdTransmitPackets (
  338. IN PIRP Irp,
  339. IN PIO_STACK_LOCATION IrpSp
  340. )
  341. /*++
  342. Routine Description:
  343. Initial entrypoint for handling transmit packets IRPs. This routine
  344. verifies parameters, initializes data structures to be used for
  345. the request, and initiates the I/O.
  346. Arguments:
  347. Irp - a pointer to a transmit file IRP.
  348. IrpSp - Our stack location for this IRP.
  349. Return Value:
  350. STATUS_PENDING if the request was initiated successfully, or a
  351. failure status code if there was an error.
  352. --*/
  353. {
  354. PAFD_ENDPOINT endpoint;
  355. NTSTATUS status;
  356. AFD_TPACKETS_INFO params;
  357. PAFD_TPACKETS_INFO_INTERNAL tpInfo = NULL;
  358. BOOLEAN irpQueued;
  359. PAGED_CODE ();
  360. //
  361. // Initial request validity checks: is the endpoint connected, is
  362. // the input buffer large enough, etc.
  363. //
  364. endpoint = IrpSp->FileObject->FsContext;
  365. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  366. //
  367. // Special hack to let the user mode dll know that it
  368. // should try SAN provider instead.
  369. //
  370. if (IS_SAN_ENDPOINT (endpoint)) {
  371. status = STATUS_INVALID_PARAMETER_12;
  372. goto complete;
  373. }
  374. //
  375. // Make sure we only execute one transmitfile transmitpackets request
  376. // at a time on a given endpoint.
  377. //
  378. if (!AFD_START_STATE_CHANGE (endpoint, endpoint->State)) {
  379. status = STATUS_INVALID_CONNECTION;
  380. goto complete;
  381. }
  382. //
  383. // The endpoint must be connected and underlying transport must support
  384. // TdiSend (not just TdiSendDatagram).
  385. //
  386. if ( (endpoint->Type != AfdBlockTypeVcConnecting &&
  387. (endpoint->Type != AfdBlockTypeDatagram ||
  388. !IS_TDI_DGRAM_CONNECTION(endpoint))) ||
  389. endpoint->State != AfdEndpointStateConnected ) {
  390. status = STATUS_INVALID_CONNECTION;
  391. goto complete_state_change;
  392. }
  393. #ifdef _WIN64
  394. if (IoIs32bitProcess (Irp)) {
  395. status = AfdTransmitPackets32 (Irp, IrpSp, &tpInfo);
  396. if (!NT_SUCCESS (status)) {
  397. goto complete_state_change;
  398. }
  399. }
  400. else
  401. #endif _WIN64
  402. {
  403. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  404. sizeof(AFD_TPACKETS_INFO) ) {
  405. status = STATUS_INVALID_PARAMETER;
  406. goto complete_state_change;
  407. }
  408. //
  409. // Because we're using type 3 (neither) I/O for this IRP, the I/O
  410. // system does no verification on the user buffer. Therefore, we
  411. // must manually check it for validity inside a try-except block.
  412. // We also leverage the try-except to validate and lock down the
  413. // head and/or tail buffers specified by the caller.
  414. //
  415. try {
  416. PFILE_OBJECT fileObject;
  417. HANDLE fileHandle;
  418. ULONG lastSmallBuffer, currentLength, xLength;
  419. ULONG maxPacketSize;
  420. if( Irp->RequestorMode != KernelMode ) {
  421. //
  422. // Validate the control buffer.
  423. //
  424. ProbeForRead(
  425. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  426. sizeof (AFD_TPACKETS_INFO),
  427. PROBE_ALIGNMENT (AFD_TPACKETS_INFO)
  428. );
  429. }
  430. params = *((PAFD_TPACKETS_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  431. //
  432. // Validate any flags specified in the request.
  433. //
  434. if ( ((params.Flags &
  435. ~(AFD_TF_WRITE_BEHIND |
  436. AFD_TF_DISCONNECT |
  437. AFD_TF_REUSE_SOCKET |
  438. AFD_TF_WORKER_KIND_MASK) )
  439. != 0 )
  440. ||
  441. ((params.Flags & AFD_TF_WORKER_KIND_MASK)
  442. == AFD_TF_WORKER_KIND_MASK)
  443. ||
  444. (endpoint->Type==AfdBlockTypeDatagram &&
  445. (params.Flags & (AFD_TF_DISCONNECT |
  446. AFD_TF_REUSE_SOCKET))
  447. !=0) ) {
  448. status = STATUS_INVALID_PARAMETER;
  449. goto complete_state_change;
  450. }
  451. //
  452. // Protect from overflow
  453. //
  454. if ((params.ElementArray==NULL) ||
  455. (params.ElementCount==0) ||
  456. (params.ElementCount>(MAXULONG/sizeof (params.ElementArray[0])))) {
  457. status = STATUS_INVALID_PARAMETER;
  458. goto complete_state_change;
  459. }
  460. //
  461. // If transmit worker is not specified, use system default setting
  462. //
  463. if ((params.Flags & AFD_TF_WORKER_KIND_MASK)==AFD_TF_USE_DEFAULT_WORKER) {
  464. params.Flags |= AfdDefaultTransmitWorker;
  465. }
  466. //
  467. // Allocate tpackets info for the request
  468. //
  469. tpInfo = AfdGetTpInfo (params.ElementCount);
  470. if (tpInfo==NULL) {
  471. status = STATUS_INSUFFICIENT_RESOURCES;
  472. goto complete_state_change;
  473. }
  474. tpInfo->SendPacketLength = params.SendSize;
  475. if (tpInfo->SendPacketLength==0)
  476. tpInfo->SendPacketLength = AfdTransmitIoLength;
  477. //
  478. // Probe and copy/walk the array of the elements to transmit.
  479. //
  480. if( Irp->RequestorMode != KernelMode ) {
  481. ProbeForRead(
  482. params.ElementArray,
  483. sizeof (TRANSMIT_PACKETS_ELEMENT)*params.ElementCount,
  484. PROBE_ALIGNMENT (TRANSMIT_PACKETS_ELEMENT)
  485. );
  486. }
  487. lastSmallBuffer = 0;
  488. currentLength = 0;
  489. fileHandle = NULL;
  490. xLength = 0;
  491. tpInfo->RemainingPkts = 0;
  492. maxPacketSize = 0;
  493. for (tpInfo->ElementCount=0;
  494. tpInfo->ElementCount<params.ElementCount;
  495. tpInfo->ElementCount++) {
  496. PAFD_TRANSMIT_PACKETS_ELEMENT pel;
  497. pel = &tpInfo->ElementArray[tpInfo->ElementCount];
  498. pel->Flags = params.ElementArray[tpInfo->ElementCount].dwElFlags;
  499. if ( ((pel->Flags & (~(TP_MEMORY|TP_FILE|TP_EOP)))!=0) ||
  500. ((pel->Flags & (TP_MEMORY|TP_FILE))
  501. ==(TP_MEMORY|TP_FILE)) ||
  502. ((pel->Flags & (TP_MEMORY|TP_FILE))==0) ) {
  503. status = STATUS_INVALID_PARAMETER;
  504. goto complete_state_change;
  505. }
  506. pel->Length = params.ElementArray[tpInfo->ElementCount].cLength;
  507. if (pel->Flags & TP_FILE) {
  508. HANDLE hFile = params.ElementArray[tpInfo->ElementCount].hFile;
  509. //
  510. // Check if we already cached the file object
  511. //
  512. if (fileHandle==NULL || hFile!=fileHandle) {
  513. //
  514. // Get a referenced pointer to the file object
  515. // for the file that we're going to transmit. This call
  516. // will fail if the file handle specified by the caller
  517. // is invalid.
  518. //
  519. status = ObReferenceObjectByHandle(
  520. hFile,
  521. FILE_READ_DATA,
  522. *IoFileObjectType,
  523. Irp->RequestorMode,
  524. (PVOID *)&fileObject,
  525. NULL
  526. );
  527. if ( !NT_SUCCESS(status) ) {
  528. //
  529. // Tell the caller that we encountered an error
  530. // when accessing file not socket.
  531. //
  532. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>=sizeof (BOOLEAN)) {
  533. if (Irp->RequestorMode != KernelMode) {
  534. ProbeAndWriteBoolean ((BOOLEAN *)Irp->UserBuffer, TRUE);
  535. }
  536. else {
  537. *((BOOLEAN *)Irp->UserBuffer) = TRUE;
  538. }
  539. }
  540. goto complete_state_change;
  541. }
  542. }
  543. else {
  544. //
  545. // Use our 1-element file info cache.
  546. //
  547. ObReferenceObject (fileObject);
  548. }
  549. AfdRecordFileRef();
  550. //
  551. // Save the file object instead of handle.
  552. //
  553. pel->FileObject = fileObject;
  554. pel->FileOffset = params.ElementArray[
  555. tpInfo->ElementCount].nFileOffset;
  556. if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) &&
  557. (pel->FileOffset.QuadPart == 0) ) {
  558. //
  559. // Use current offset if file is opened syncronously
  560. // and offset is not specified.
  561. //
  562. pel->FileOffset = fileObject->CurrentByteOffset;
  563. }
  564. if ( pel->Length == 0 ) {
  565. //
  566. // Length was not specified, figure out the
  567. // size of the entire file
  568. //
  569. FILE_STANDARD_INFORMATION fileInfo;
  570. IO_STATUS_BLOCK ioStatusBlock;
  571. status = ZwQueryInformationFile(
  572. hFile,
  573. &ioStatusBlock,
  574. &fileInfo,
  575. sizeof(fileInfo),
  576. FileStandardInformation
  577. );
  578. if ( !NT_SUCCESS(status) ) {
  579. //
  580. // Bump element count so that file object
  581. // is dereferenced in cleanup
  582. //
  583. tpInfo->ElementCount += 1;
  584. //
  585. // Tell the caller that we encountered an error
  586. // when accessing file not socket.
  587. //
  588. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>=sizeof (BOOLEAN)) {
  589. if (Irp->RequestorMode != KernelMode) {
  590. ProbeAndWriteBoolean ((BOOLEAN *)Irp->UserBuffer, TRUE);
  591. }
  592. else {
  593. *((BOOLEAN *)Irp->UserBuffer) = TRUE;
  594. }
  595. }
  596. goto complete_state_change;
  597. }
  598. //
  599. // Make sure that offset is within the file
  600. //
  601. if (pel->FileOffset.QuadPart < 0
  602. ||
  603. pel->FileOffset.QuadPart > fileInfo.EndOfFile.QuadPart
  604. ||
  605. (fileInfo.EndOfFile.QuadPart -
  606. pel->FileOffset.QuadPart > MAXLONG)) {
  607. //
  608. // Bump element count so that file object
  609. // is dereferenced in cleanup
  610. //
  611. tpInfo->ElementCount += 1;
  612. status = STATUS_INVALID_PARAMETER;
  613. goto complete_state_change;
  614. }
  615. pel->Length = (ULONG)(fileInfo.EndOfFile.QuadPart -
  616. pel->FileOffset.QuadPart);
  617. }
  618. else if (pel->FileOffset.QuadPart<0) {
  619. //
  620. // Bump element count so that file object
  621. // is dereferenced in cleanup
  622. //
  623. tpInfo->ElementCount += 1;
  624. status = STATUS_INVALID_PARAMETER;
  625. goto complete_state_change;
  626. }
  627. //
  628. // Update our 1-element file information cache
  629. //
  630. fileHandle = hFile;
  631. }
  632. else {
  633. ASSERT (pel->Flags & TP_MEMORY);
  634. //
  635. // For memory object just save the buffer pointer
  636. // (length is saved above), we'll probe and lock/copy
  637. // the data as we send it.
  638. //
  639. pel->Buffer = params.ElementArray[
  640. tpInfo->ElementCount].pBuffer;
  641. if (pel->Length<=AfdTPacketsCopyThreshold) {
  642. if (lastSmallBuffer!=0 &&
  643. (lastSmallBuffer+=pel->Length) <= AfdTPacketsCopyThreshold &&
  644. (currentLength+lastSmallBuffer) <= tpInfo->SendPacketLength) {
  645. (pel-1)->Flags |= TP_COMBINE;
  646. }
  647. else
  648. lastSmallBuffer = pel->Length;
  649. if (!(pel->Flags & TP_EOP))
  650. goto NoBufferReset;
  651. }
  652. }
  653. lastSmallBuffer = 0;
  654. NoBufferReset:
  655. if (pel->Flags & TP_EOP) {
  656. currentLength = 0;
  657. }
  658. else {
  659. currentLength = (currentLength+pel->Length)%tpInfo->SendPacketLength;
  660. }
  661. //
  662. // Compute the total number of packets that we will send.
  663. // This is necessary so that once we are close to the end
  664. // we can buffer the remaining data and stop processing
  665. // early.
  666. //
  667. if (tpInfo->RemainingPkts!=MAXULONG) {
  668. ULONG n;
  669. ULONGLONG x;
  670. //
  671. // Add length of the element to data left from the
  672. // previous one.
  673. //
  674. x = xLength + pel->Length;
  675. //
  676. // Compute total number of packets pased on max packet
  677. // length.
  678. //
  679. n = tpInfo->RemainingPkts + (ULONG)(xLength/tpInfo->SendPacketLength);
  680. //
  681. // Compute the length of the last incomplete packet to
  682. // be combined with the next element.
  683. //
  684. xLength = (ULONG)(x%tpInfo->SendPacketLength);
  685. //
  686. // Compute the max size of the packet
  687. //
  688. if (x>tpInfo->SendPacketLength)
  689. maxPacketSize = tpInfo->SendPacketLength; // This is absolute max.
  690. else if (maxPacketSize<xLength)
  691. maxPacketSize = xLength;
  692. if (n>=tpInfo->RemainingPkts && n<MAXULONG) {
  693. tpInfo->RemainingPkts = n;
  694. if (pel->Flags & TP_EOP) {
  695. if (xLength!=0 || pel->Length==0) {
  696. tpInfo->RemainingPkts += 1;
  697. xLength = 0;
  698. }
  699. }
  700. }
  701. else {
  702. tpInfo->RemainingPkts = MAXULONG;
  703. }
  704. }
  705. }
  706. if (maxPacketSize==0) {
  707. maxPacketSize = tpInfo->SendPacketLength;
  708. }
  709. //
  710. // Compute the total number of IRPS to use based
  711. // on SO_SNDBUF setting and maximum packet size
  712. // (we do not want to buffer more than SO_SNDBUF).
  713. //
  714. {
  715. ULONG maxSendBytes, irpCount;
  716. if (endpoint->Type==AfdBlockTypeVcConnecting) {
  717. maxSendBytes = endpoint->Common.VcConnecting.Connection->MaxBufferredSendBytes;
  718. }
  719. else {
  720. ASSERT (endpoint->Type==AfdBlockTypeDatagram);
  721. maxSendBytes = endpoint->Common.Datagram.MaxBufferredSendBytes;
  722. }
  723. irpCount = maxSendBytes/maxPacketSize;
  724. if (irpCount>AFD_TP_MIN_SEND_IRPS) {
  725. if (irpCount>AFD_TP_MAX_SEND_IRPS) {
  726. tpInfo->NumSendIrps = AFD_TP_MAX_SEND_IRPS;
  727. }
  728. else {
  729. tpInfo->NumSendIrps = (USHORT)irpCount;
  730. }
  731. }
  732. }
  733. //
  734. // Initialize flags.
  735. //
  736. IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags = params.Flags;
  737. } except( AFD_EXCEPTION_FILTER(&status) ) {
  738. goto complete_state_change;
  739. }
  740. }
  741. if (endpoint->Type==AfdBlockTypeVcConnecting) {
  742. //
  743. // Connection endpoint, get connection file object and device
  744. //
  745. tpInfo->TdiFileObject =
  746. endpoint->Common.VcConnecting.Connection->FileObject;
  747. tpInfo->TdiDeviceObject =
  748. endpoint->Common.VcConnecting.Connection->DeviceObject;
  749. //
  750. // Setting AFD_TF_REUSE_SOCKET implies that a disconnect is desired.
  751. // Also, setting this flag means that no more I/O is legal on the
  752. // endpoint until the transmit request has been completed, so
  753. // set up the endpoint's state so that I/O fails.
  754. //
  755. if ( (IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_REUSE_SOCKET) != 0 ) {
  756. IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags |= AFD_TF_DISCONNECT;
  757. endpoint->State = AfdEndpointStateTransmitClosing;
  758. }
  759. UPDATE_TPACKETS2 (Irp, "Connection object handle: %lx",
  760. HandleToUlong (endpoint->Common.VcConnecting.Connection->Handle));
  761. }
  762. else {
  763. //
  764. // Datagram endpoint, get address file object and device
  765. //
  766. ASSERT (endpoint->Type==AfdBlockTypeDatagram);
  767. tpInfo->TdiFileObject = endpoint->AddressFileObject;
  768. tpInfo->TdiDeviceObject = endpoint->AddressDeviceObject;
  769. UPDATE_TPACKETS2 (Irp, "Address object handle: %lx", HandleToUlong (endpoint->AddressHandle));
  770. }
  771. //
  772. // Save tpacket info in the IRP
  773. //
  774. Irp->AssociatedIrp.SystemBuffer = tpInfo;
  775. //
  776. // Clear the Flink in the IRP to indicate this IRP is not queued.
  777. // Blink is cleared to indicate that IRP was counted towards
  778. // active maximum.
  779. //
  780. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  781. Irp->Tail.Overlay.ListEntry.Blink = NULL;
  782. //
  783. // Initialize the IRP result fields
  784. //
  785. Irp->IoStatus.Status = STATUS_SUCCESS;
  786. Irp->IoStatus.Information = 0;
  787. //
  788. // We are going to pend this IRP
  789. //
  790. IoMarkIrpPending( Irp );
  791. //
  792. // Initialize queuing and state information.
  793. //
  794. InitializeListHead (&AFD_GET_TPIC(Irp)->EndpQueueEntry);
  795. AFD_GET_TPIC(Irp)->ReferenceCount = 1;
  796. AFD_GET_TPIC(Irp)->StateFlags = AFD_TP_WORKER_SCHEDULED;
  797. irpQueued = (InterlockedCompareExchangePointer ((PVOID *)&endpoint->Irp,
  798. Irp,
  799. NULL)!=NULL) &&
  800. AfdEnqueueTPacketsIrp (endpoint, Irp);
  801. //
  802. // If disconnect is not specified, end state change.
  803. // This will permit queuing of another transmit IRP
  804. //
  805. if (!(IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT)) {
  806. AFD_END_STATE_CHANGE (endpoint);
  807. }
  808. IoSetCancelRoutine( Irp, AfdCancelTPackets );
  809. //
  810. // Check to see if this Irp has been cancelled.
  811. //
  812. if ( !Irp->Cancel ) {
  813. if (irpQueued) {
  814. DEREFERENCE_TPACKETS (Irp);
  815. }
  816. else {
  817. //
  818. // Determine if we can really start this file transmit now. If we've
  819. // exceeded the configured maximum number of active TransmitFile/Packets
  820. // requests, then append this IRP to the TransmitFile/Packets queue
  821. // and set a flag in the transmit info structure to indicate that
  822. // this IRP is queued.
  823. //
  824. if( AfdMaxActiveTransmitFileCount == 0 ||
  825. !AfdQueueTransmit (Irp)) {
  826. //
  827. // Start I/O
  828. //
  829. AfdTPacketsWorker (Irp);
  830. }
  831. }
  832. }
  833. else {
  834. //
  835. // Abort the request
  836. // Note that neither cancel nor endpoint cleanup can complete
  837. // the IRP since we hold the reference to the tpInfo structure.
  838. //
  839. AfdAbortTPackets (Irp, STATUS_CANCELLED);
  840. //
  841. // Remove the initial reference and force completion.
  842. //
  843. DEREFERENCE_TPACKETS (Irp);
  844. }
  845. return STATUS_PENDING;
  846. complete_state_change:
  847. ASSERT ( endpoint->Irp != Irp );
  848. AFD_END_STATE_CHANGE (endpoint);
  849. if (tpInfo!=NULL) {
  850. //
  851. // AfdReturnTpInfo will dereference all file objects we
  852. // managed to reference.
  853. //
  854. AfdReturnTpInfo (tpInfo);
  855. }
  856. complete:
  857. IF_DEBUG (TRANSMIT) {
  858. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  859. "AfdTransmitPackets: Failing Irp-%p,endpoint-%p,status-%lx\n",
  860. Irp,endpoint,status));
  861. }
  862. //
  863. // Complete the request.
  864. //
  865. Irp->IoStatus.Information = 0;
  866. Irp->IoStatus.Status = status;
  867. IoCompleteRequest( Irp, 0 );
  868. return status;
  869. }
  870. #ifdef _WIN64
  871. NTSTATUS
  872. AfdTransmitPackets32 (
  873. IN PIRP Irp,
  874. IN PIO_STACK_LOCATION IrpSp,
  875. OUT PAFD_TPACKETS_INFO_INTERNAL *TpInfo
  876. )
  877. /*++
  878. Routine Description:
  879. 32-bit thunk.
  880. Initial entrypoint for handling transmit packets IRPs. This routine
  881. verifies parameters, initializes data structures to be used for
  882. the request, and initiates the I/O.
  883. Arguments:
  884. Irp - a pointer to a transmit file IRP.
  885. IrpSp - Our stack location for this IRP.
  886. Return Value:
  887. STATUS_PENDING if the request was initiated successfully, or a
  888. failure status code if there was an error.
  889. --*/
  890. {
  891. PAFD_ENDPOINT endpoint;
  892. NTSTATUS status = STATUS_SUCCESS;
  893. AFD_TPACKETS_INFO32 params;
  894. PAFD_TPACKETS_INFO_INTERNAL tpInfo = NULL;
  895. PAGED_CODE ();
  896. //
  897. // Initial request validity checks: is the endpoint connected, is
  898. // the input buffer large enough, etc.
  899. //
  900. endpoint = IrpSp->FileObject->FsContext;
  901. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  902. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  903. sizeof(AFD_TPACKETS_INFO32) ) {
  904. status = STATUS_INVALID_PARAMETER;
  905. goto complete;
  906. }
  907. //
  908. // Because we're using type 3 (neither) I/O for this IRP, the I/O
  909. // system does no verification on the user buffer. Therefore, we
  910. // must manually check it for validity inside a try-except block.
  911. // We also leverage the try-except to validate and lock down the
  912. // head and/or tail buffers specified by the caller.
  913. //
  914. try {
  915. PFILE_OBJECT fileObject;
  916. HANDLE fileHandle;
  917. ULONG lastSmallBuffer, currentLength, xLength;
  918. ULONG maxPacketSize;
  919. if( Irp->RequestorMode != KernelMode ) {
  920. //
  921. // Validate the control buffer.
  922. //
  923. ProbeForRead(
  924. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  925. sizeof (AFD_TPACKETS_INFO32),
  926. PROBE_ALIGNMENT32 (AFD_TPACKETS_INFO32)
  927. );
  928. }
  929. params = *((PAFD_TPACKETS_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  930. //
  931. // Validate any flags specified in the request.
  932. //
  933. if ( ((params.Flags &
  934. ~(AFD_TF_WRITE_BEHIND |
  935. AFD_TF_DISCONNECT |
  936. AFD_TF_REUSE_SOCKET |
  937. AFD_TF_WORKER_KIND_MASK) )
  938. != 0 )
  939. ||
  940. ((params.Flags & AFD_TF_WORKER_KIND_MASK)
  941. == AFD_TF_WORKER_KIND_MASK)
  942. ||
  943. (endpoint->Type==AfdBlockTypeDatagram &&
  944. (params.Flags & (AFD_TF_DISCONNECT |
  945. AFD_TF_REUSE_SOCKET))
  946. !=0) ) {
  947. status = STATUS_INVALID_PARAMETER;
  948. goto complete;
  949. }
  950. //
  951. // Protect from overflow
  952. //
  953. if ((params.ElementArray==NULL) ||
  954. (params.ElementCount==0) ||
  955. (params.ElementCount>(MAXULONG/sizeof (params.ElementArray[0])))) {
  956. status = STATUS_INVALID_PARAMETER;
  957. goto complete;
  958. }
  959. //
  960. // If transmit worker is not specified, use system default setting
  961. //
  962. if ((params.Flags & AFD_TF_WORKER_KIND_MASK)==AFD_TF_USE_DEFAULT_WORKER) {
  963. params.Flags |= AfdDefaultTransmitWorker;
  964. }
  965. //
  966. // Allocate tpackets info for the request
  967. //
  968. tpInfo = AfdGetTpInfo (params.ElementCount);
  969. if (tpInfo==NULL) {
  970. status = STATUS_INSUFFICIENT_RESOURCES;
  971. goto complete;
  972. }
  973. tpInfo->SendPacketLength = params.SendSize;
  974. if (tpInfo->SendPacketLength==0)
  975. tpInfo->SendPacketLength = AfdTransmitIoLength;
  976. //
  977. // Probe and copy/walk the array of the elements to transmit.
  978. //
  979. if( Irp->RequestorMode != KernelMode ) {
  980. ProbeForRead(
  981. params.ElementArray,
  982. sizeof (TRANSMIT_PACKETS_ELEMENT32)*params.ElementCount,
  983. PROBE_ALIGNMENT32 (TRANSMIT_PACKETS_ELEMENT32)
  984. );
  985. }
  986. lastSmallBuffer = 0;
  987. currentLength = 0;
  988. fileHandle = NULL;
  989. xLength = 0;
  990. tpInfo->RemainingPkts = 0;
  991. maxPacketSize = 0;
  992. for (tpInfo->ElementCount=0;
  993. tpInfo->ElementCount<params.ElementCount;
  994. tpInfo->ElementCount++) {
  995. PAFD_TRANSMIT_PACKETS_ELEMENT pel;
  996. pel = &tpInfo->ElementArray[tpInfo->ElementCount];
  997. pel->Flags = params.ElementArray[tpInfo->ElementCount].dwElFlags;
  998. if ( ((pel->Flags & (~(TP_MEMORY|TP_FILE|TP_EOP)))!=0) ||
  999. ((pel->Flags & (TP_MEMORY|TP_FILE))
  1000. ==(TP_MEMORY|TP_FILE)) ||
  1001. ((pel->Flags & (TP_MEMORY|TP_FILE))==0) ) {
  1002. status = STATUS_INVALID_PARAMETER;
  1003. goto complete;
  1004. }
  1005. pel->Length = params.ElementArray[tpInfo->ElementCount].cLength;
  1006. if (pel->Flags & TP_FILE) {
  1007. HANDLE hFile = params.ElementArray[tpInfo->ElementCount].hFile;
  1008. //
  1009. // Check if we already cached the file object
  1010. //
  1011. if (fileHandle==NULL || hFile!=fileHandle) {
  1012. //
  1013. // Get a referenced pointer to the file object
  1014. // for the file that we're going to transmit. This call
  1015. // will fail if the file handle specified by the caller
  1016. // is invalid.
  1017. //
  1018. status = ObReferenceObjectByHandle(
  1019. hFile,
  1020. FILE_READ_DATA,
  1021. *IoFileObjectType,
  1022. Irp->RequestorMode,
  1023. (PVOID *)&fileObject,
  1024. NULL
  1025. );
  1026. if ( !NT_SUCCESS(status) ) {
  1027. //
  1028. // Tell the caller that we encountered an error
  1029. // when accessing file not socket.
  1030. //
  1031. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>=sizeof (BOOLEAN)) {
  1032. if (Irp->RequestorMode != KernelMode) {
  1033. ProbeAndWriteBoolean ((BOOLEAN *)Irp->UserBuffer, TRUE);
  1034. }
  1035. else {
  1036. *((BOOLEAN *)Irp->UserBuffer) = TRUE;
  1037. }
  1038. }
  1039. goto complete;
  1040. }
  1041. }
  1042. else {
  1043. //
  1044. // Use our 1-element file info cache.
  1045. //
  1046. ObReferenceObject (fileObject);
  1047. }
  1048. AfdRecordFileRef();
  1049. //
  1050. // Save the file object instead of handle.
  1051. //
  1052. pel->FileObject = fileObject;
  1053. pel->FileOffset = params.ElementArray[
  1054. tpInfo->ElementCount].nFileOffset;
  1055. if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) &&
  1056. (pel->FileOffset.QuadPart == 0) ) {
  1057. //
  1058. // Use current offset if file is opened syncronously
  1059. // and offset is not specified.
  1060. //
  1061. pel->FileOffset = fileObject->CurrentByteOffset;
  1062. }
  1063. if ( pel->Length == 0 ) {
  1064. //
  1065. // Length was not specified, figure out the
  1066. // size of the entire file
  1067. //
  1068. FILE_STANDARD_INFORMATION fileInfo;
  1069. IO_STATUS_BLOCK ioStatusBlock;
  1070. status = ZwQueryInformationFile(
  1071. hFile,
  1072. &ioStatusBlock,
  1073. &fileInfo,
  1074. sizeof(fileInfo),
  1075. FileStandardInformation
  1076. );
  1077. if ( !NT_SUCCESS(status) ) {
  1078. //
  1079. // Bump element count so that file object
  1080. // is dereferenced in cleanup
  1081. //
  1082. tpInfo->ElementCount += 1;
  1083. //
  1084. // Tell the caller that we encountered an error
  1085. // when accessing file not socket.
  1086. //
  1087. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>=sizeof (BOOLEAN)) {
  1088. if (Irp->RequestorMode != KernelMode) {
  1089. ProbeAndWriteBoolean ((BOOLEAN *)Irp->UserBuffer, TRUE);
  1090. }
  1091. else {
  1092. *((BOOLEAN *)Irp->UserBuffer) = TRUE;
  1093. }
  1094. }
  1095. goto complete;
  1096. }
  1097. //
  1098. // Make sure that offset is within the file
  1099. //
  1100. if (pel->FileOffset.QuadPart < 0
  1101. ||
  1102. pel->FileOffset.QuadPart > fileInfo.EndOfFile.QuadPart
  1103. ||
  1104. (fileInfo.EndOfFile.QuadPart -
  1105. pel->FileOffset.QuadPart > MAXLONG)) {
  1106. //
  1107. // Bump element count so that file object
  1108. // is dereferenced in cleanup
  1109. //
  1110. tpInfo->ElementCount += 1;
  1111. status = STATUS_INVALID_PARAMETER;
  1112. goto complete;
  1113. }
  1114. pel->Length = (ULONG)(fileInfo.EndOfFile.QuadPart -
  1115. pel->FileOffset.QuadPart);
  1116. }
  1117. else if (pel->FileOffset.QuadPart<0) {
  1118. //
  1119. // Bump element count so that file object
  1120. // is dereferenced in cleanup
  1121. //
  1122. tpInfo->ElementCount += 1;
  1123. status = STATUS_INVALID_PARAMETER;
  1124. goto complete;
  1125. }
  1126. //
  1127. // Update our 1-element file information cache
  1128. //
  1129. fileHandle = hFile;
  1130. }
  1131. else {
  1132. ASSERT (pel->Flags & TP_MEMORY);
  1133. //
  1134. // For memory object just save the buffer pointer
  1135. // (length is saved above), we'll probe and lock/copy
  1136. // the data as we send it.
  1137. //
  1138. pel->Buffer = params.ElementArray[
  1139. tpInfo->ElementCount].pBuffer;
  1140. if (pel->Length<=AfdTPacketsCopyThreshold) {
  1141. if (lastSmallBuffer!=0 &&
  1142. (lastSmallBuffer+=pel->Length) <= AfdTPacketsCopyThreshold &&
  1143. (currentLength+lastSmallBuffer) <= tpInfo->SendPacketLength) {
  1144. (pel-1)->Flags |= TP_COMBINE;
  1145. }
  1146. else
  1147. lastSmallBuffer = pel->Length;
  1148. if (!(pel->Flags & TP_EOP))
  1149. goto NoBufferReset;
  1150. }
  1151. }
  1152. lastSmallBuffer = 0;
  1153. NoBufferReset:
  1154. if (pel->Flags & TP_EOP) {
  1155. currentLength = 0;
  1156. }
  1157. else {
  1158. currentLength = (currentLength+pel->Length)%tpInfo->SendPacketLength;
  1159. }
  1160. //
  1161. // Compute the total number of packets that we will send.
  1162. // This is necessary so that once we are close to the end
  1163. // we can buffer the remaining data and stop processing
  1164. // early.
  1165. //
  1166. if (tpInfo->RemainingPkts!=MAXULONG) {
  1167. ULONG n;
  1168. ULONGLONG x;
  1169. //
  1170. // Add length of the element to data left from the
  1171. // previous one.
  1172. //
  1173. x = xLength + pel->Length;
  1174. //
  1175. // Compute total number of packets pased on max packet
  1176. // length.
  1177. //
  1178. n = tpInfo->RemainingPkts + (ULONG)(xLength/tpInfo->SendPacketLength);
  1179. //
  1180. // Compute the length of the last incomplete packet to
  1181. // be combined with the next element.
  1182. //
  1183. xLength = (ULONG)(x%tpInfo->SendPacketLength);
  1184. //
  1185. // Compute the max size of the packet
  1186. //
  1187. if (x>tpInfo->SendPacketLength)
  1188. maxPacketSize = tpInfo->SendPacketLength; // This is absolute max.
  1189. else if (maxPacketSize<xLength)
  1190. maxPacketSize = xLength;
  1191. if (n>=tpInfo->RemainingPkts && n<MAXULONG) {
  1192. tpInfo->RemainingPkts = n;
  1193. if (pel->Flags & TP_EOP) {
  1194. if (xLength!=0 || pel->Length==0) {
  1195. tpInfo->RemainingPkts += 1;
  1196. xLength = 0;
  1197. }
  1198. }
  1199. }
  1200. else {
  1201. tpInfo->RemainingPkts = MAXULONG;
  1202. }
  1203. }
  1204. }
  1205. if (maxPacketSize==0) {
  1206. maxPacketSize = tpInfo->SendPacketLength;
  1207. }
  1208. //
  1209. // Compute the total number of IRPS to use based
  1210. // on SO_SNDBUF setting and maximum packet size
  1211. // (we do not want to buffer more than SO_SNDBUF).
  1212. //
  1213. {
  1214. ULONG maxSendBytes, irpCount;
  1215. if (endpoint->Type==AfdBlockTypeVcConnecting) {
  1216. maxSendBytes = endpoint->Common.VcConnecting.Connection->MaxBufferredSendBytes;
  1217. }
  1218. else {
  1219. ASSERT (endpoint->Type==AfdBlockTypeDatagram);
  1220. maxSendBytes = endpoint->Common.Datagram.MaxBufferredSendBytes;
  1221. }
  1222. irpCount = maxSendBytes/maxPacketSize;
  1223. if (irpCount>AFD_TP_MIN_SEND_IRPS) {
  1224. if (irpCount>AFD_TP_MAX_SEND_IRPS) {
  1225. tpInfo->NumSendIrps = AFD_TP_MAX_SEND_IRPS;
  1226. }
  1227. else {
  1228. tpInfo->NumSendIrps = (USHORT)irpCount;
  1229. }
  1230. }
  1231. }
  1232. //
  1233. // Initialize flags.
  1234. //
  1235. IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags = params.Flags;
  1236. } except( AFD_EXCEPTION_FILTER(&status) ) {
  1237. goto complete;
  1238. }
  1239. complete:
  1240. *TpInfo = tpInfo;
  1241. return status;
  1242. }
  1243. #endif //_WIN64
  1244. VOID
  1245. AfdTPacketsWorker (
  1246. PVOID Context
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. Transmit packet engine
  1251. Scheduled as system work item or kernel APC
  1252. Arguments:
  1253. Context - pointer to TransmitPackets info for the request
  1254. Return Value:
  1255. None.
  1256. --*/
  1257. {
  1258. PIRP TpIrp = Context;
  1259. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  1260. NTSTATUS status;
  1261. LONG iteration = 0;
  1262. PAGED_CODE ();
  1263. #if AFD_PERF_DBG
  1264. tpInfo->WorkersExecuted += 1;
  1265. #endif
  1266. UPDATE_TPACKETS2 (TpIrp, "Enter TPWorker, next element: %ld", tpInfo->NextElement);
  1267. IF_DEBUG (TRANSMIT) {
  1268. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1269. "AfdTPacketsWorker:"
  1270. " Entering for endpoint-%p,tp_info-%p,elem-%d\n",
  1271. IoGetCurrentIrpStackLocation (TpIrp)->FileObject->FsContext,
  1272. tpInfo,tpInfo->NextElement));
  1273. }
  1274. //
  1275. // Continue while we have more elements to transmit or something to free
  1276. //
  1277. do {
  1278. PAFD_BUFFER_HEADER pd;
  1279. //
  1280. // Check if we need to release packet chain that was already sent.
  1281. //
  1282. if ((tpInfo->HeadMdl!=NULL) && (tpInfo->TailMdl==&tpInfo->HeadMdl)) {
  1283. AfdCleanupPacketChain (TpIrp, TRUE);
  1284. }
  1285. //
  1286. // Check if we are done.
  1287. //
  1288. if (tpInfo->NextElement>=tpInfo->ElementCount) {
  1289. //
  1290. // Handle special case of using TransmitFile to just disconnect
  1291. // (and possibly reuse) the socket.
  1292. //
  1293. if (tpInfo->ElementCount==0) {
  1294. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(TpIrp);
  1295. PAFD_ENDPOINT endpoint = irpSp->FileObject->FsContext;
  1296. if (irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT) {
  1297. ASSERT (endpoint->Type==AfdBlockTypeVcConnecting);
  1298. ASSERT (endpoint->Common.VcConnecting.Connection!=NULL);
  1299. status = AfdBeginDisconnect(
  1300. endpoint,
  1301. NULL,
  1302. NULL
  1303. );
  1304. if (NT_SUCCESS (status)) {
  1305. IF_DEBUG (TRANSMIT) {
  1306. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1307. "AfdTPacketsWorker: Initiated disconnect, tpInfo-%p,status-%lx\n",
  1308. tpInfo, status));
  1309. }
  1310. //
  1311. // Return pending to exit the worker
  1312. // and complete the request.
  1313. //
  1314. status = STATUS_PENDING;
  1315. }
  1316. else {
  1317. //
  1318. // Disconnect failed, we'll have to abort below.
  1319. //
  1320. IF_DEBUG (TRANSMIT) {
  1321. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1322. "AfdTPacketsWorker: tpInfo-%p, begin discon failed: %lx\n",
  1323. tpInfo, status));
  1324. }
  1325. }
  1326. }
  1327. else {
  1328. //
  1329. // Well, no disconnect and nothing to transmit.
  1330. // Why were called at all? We'll have to handle this anyway.
  1331. //
  1332. AfdStartNextTPacketsIrp (endpoint, TpIrp);
  1333. status = STATUS_PENDING;
  1334. }
  1335. }
  1336. else {
  1337. status = STATUS_PENDING;
  1338. }
  1339. break;
  1340. }
  1341. //
  1342. // Start building new chain
  1343. //
  1344. status = AfdBuildPacketChain (TpIrp, &pd);
  1345. if (status==STATUS_SUCCESS) {
  1346. USHORT sendIrp;
  1347. //
  1348. // New chain is ready, find and IRP to send it
  1349. //
  1350. sendIrp = AfdTPacketsFindSendIrp (TpIrp);
  1351. if (sendIrp!=tpInfo->NumSendIrps) {
  1352. //
  1353. // Found send IRP, perform send and continue.
  1354. //
  1355. status = AfdTPacketsSend (TpIrp, sendIrp);
  1356. }
  1357. else {
  1358. //
  1359. // Exit worker waiting for sends to complete.
  1360. //
  1361. status = STATUS_PENDING;
  1362. }
  1363. }
  1364. else if (status==STATUS_PENDING) {
  1365. //
  1366. // Need to perform a read.
  1367. // If read complete in-line, success is returned,
  1368. // otherwise, we'll get STATUS_PENDING or error
  1369. //
  1370. if (AFD_USE_CACHE (pd->FileObject)) {
  1371. status = AfdTPacketsMdlRead (TpIrp, pd);
  1372. }
  1373. else {
  1374. status = AfdTPacketsBufferRead (TpIrp, pd);
  1375. }
  1376. }
  1377. //
  1378. // Continue while everything completes in-line with success
  1379. // Limit number of iterations if we are at APC level.
  1380. //
  1381. }
  1382. while (status==STATUS_SUCCESS && iteration++<tpInfo->NumSendIrps);
  1383. if (NT_SUCCESS (status)) {
  1384. if (status==STATUS_SUCCESS) {
  1385. //
  1386. // Exceeded number of iterations.
  1387. // Reschedule the APC. Transfer the reference to the
  1388. // worker.
  1389. //
  1390. ASSERT (iteration==tpInfo->NumSendIrps+1);
  1391. ASSERT (AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED);
  1392. UPDATE_TPACKETS2 (TpIrp, "Rescheduling tp worker, NextElement: %ld",
  1393. tpInfo->NextElement);
  1394. AfdStartTPacketsWorker (AfdTPacketsWorker, TpIrp);
  1395. return;
  1396. }
  1397. else {
  1398. ASSERT (status==STATUS_PENDING);
  1399. }
  1400. }
  1401. else {
  1402. //
  1403. // Something failed, abort.
  1404. //
  1405. AfdAbortTPackets (TpIrp, status);
  1406. }
  1407. IF_DEBUG (TRANSMIT) {
  1408. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1409. "AfdTPacketsWorker:"
  1410. " Exiting for endpoint-%p,tp_info-%p,elem-%d\n",
  1411. IoGetCurrentIrpStackLocation (TpIrp)->FileObject->FsContext,
  1412. tpInfo,tpInfo->NextElement));
  1413. }
  1414. //
  1415. // Remove the reference added when we scheduled the worker.
  1416. //
  1417. DEREFERENCE_TPACKETS (TpIrp);
  1418. }
  1419. NTSTATUS
  1420. AfdBuildPacketChain (
  1421. PIRP TpIrp,
  1422. PAFD_BUFFER_HEADER *Pd
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. Builds MDL chain for a packet using packet descriptors.
  1427. Arguments:
  1428. TpIrp - transmit packets IRP
  1429. Return Value:
  1430. STATUS_SUCCESS - packet is fully built
  1431. STATUS_PENDING - file read is required
  1432. other - failure.
  1433. --*/
  1434. {
  1435. NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
  1436. BOOLEAN attached = FALSE;
  1437. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  1438. PAFD_ENDPOINT endpoint = IoGetCurrentIrpStackLocation (TpIrp)->FileObject->FsContext;
  1439. PAFD_TRANSMIT_PACKETS_ELEMENT combinePel = NULL;
  1440. ULONG combineLen = 0;
  1441. //
  1442. // Either we have something built or both MDL and PD are empty
  1443. //
  1444. ASSERT (tpInfo->PdLength>0 ||
  1445. ((tpInfo->HeadMdl==NULL || tpInfo->HeadMdl->ByteCount==0)
  1446. && (tpInfo->HeadPd==NULL || tpInfo->HeadPd->DataLength==0)) );
  1447. //
  1448. // Continue while we haven't got a complet packet and
  1449. // have elements to process
  1450. //
  1451. while (status==STATUS_MORE_PROCESSING_REQUIRED) {
  1452. PAFD_TRANSMIT_PACKETS_ELEMENT pel;
  1453. PMDL mdl;
  1454. ULONG length;
  1455. //
  1456. // Get next element to process
  1457. //
  1458. pel = &tpInfo->ElementArray[tpInfo->NextElement];
  1459. IF_DEBUG (TRANSMIT) {
  1460. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1461. "AfdBuildPacketChain: tpInfo-%p, pel:%p\n",
  1462. tpInfo, pel));
  1463. }
  1464. //
  1465. // Snag the element length
  1466. //
  1467. length = pel->Length;
  1468. if (length+tpInfo->PdLength>tpInfo->SendPacketLength) {
  1469. //
  1470. // We hit packet length limit, take what we can
  1471. //
  1472. length = tpInfo->SendPacketLength-tpInfo->PdLength;
  1473. //
  1474. // Indicate that we are done
  1475. //
  1476. status = STATUS_SUCCESS;
  1477. IF_DEBUG (TRANSMIT) {
  1478. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1479. "AfdBuildPacketChain:"
  1480. " tpInfo-%p, exceeded send length(%ld)\n",
  1481. tpInfo, tpInfo->SendPacketLength));
  1482. }
  1483. }
  1484. else {
  1485. //
  1486. // We are finished with the current element. We will consume it
  1487. // (or fail), go to the next one
  1488. //
  1489. tpInfo->NextElement += 1;
  1490. //
  1491. // Check for a complete packet or manual packetization flag set
  1492. // by the application or just end of element array
  1493. //
  1494. if ((length+tpInfo->PdLength==tpInfo->SendPacketLength) ||
  1495. (pel->Flags & TP_EOP) ||
  1496. (tpInfo->NextElement>=tpInfo->ElementCount)) {
  1497. status = STATUS_SUCCESS;
  1498. IF_DEBUG (TRANSMIT) {
  1499. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1500. "AfdBuildPacketChain:"
  1501. " tpInfo-%p, full length, EOP, or last %ld\n",
  1502. tpInfo, tpInfo->NextElement));
  1503. }
  1504. }
  1505. }
  1506. //
  1507. // Adjust the remaining lenght of data in the current element
  1508. // and the length of the packet that we are building.
  1509. //
  1510. pel->Length -= length;
  1511. tpInfo->PdLength += length;
  1512. if (length==0) {
  1513. tpInfo->PdNeedsPps = TRUE; // Don't have a buffer to get an IRP from.
  1514. mdl = IoAllocateMdl (tpInfo, 1, FALSE, FALSE, NULL);
  1515. if (mdl==NULL) {
  1516. status = STATUS_INSUFFICIENT_RESOURCES;
  1517. break;
  1518. }
  1519. MmBuildMdlForNonPagedPool( mdl );
  1520. mdl->ByteCount = 0;
  1521. IF_DEBUG (TRANSMIT) {
  1522. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1523. "AfdBuildPacketChain:"
  1524. " tpInfo-%p, 0-length MDL %p\n",
  1525. tpInfo,mdl));
  1526. }
  1527. //
  1528. // Insert MDL into the MDL chain
  1529. //
  1530. *(tpInfo->TailMdl) = mdl;
  1531. tpInfo->TailMdl = &(mdl->Next);
  1532. }
  1533. else if (pel->Flags & TP_MEMORY) {
  1534. //
  1535. // Memory block processing
  1536. //
  1537. if (pel->Flags & TP_MDL) {
  1538. tpInfo->PdNeedsPps = TRUE; // Need to make sure that process
  1539. // memory is there until send completes.
  1540. //
  1541. // This a pre-built MDL (TransmitFile header or trailer buffer)
  1542. //
  1543. if (pel->Mdl->ByteCount==length) {
  1544. mdl = pel->Mdl;
  1545. pel->Mdl = NULL;
  1546. IF_DEBUG (TRANSMIT) {
  1547. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1548. "AfdBuildPacketChain:"
  1549. " tpInfo-%p, pre-built mdl-%p(%lx)\n",
  1550. tpInfo, mdl, mdl->ByteCount));
  1551. }
  1552. }
  1553. else {
  1554. //
  1555. // We can't send the whole thing at once since it is
  1556. // bigger than the packet lenght, build partial MDL
  1557. // for this - it is very unlikely scenario for header
  1558. // and/or trailer.
  1559. //
  1560. mdl = IoAllocateMdl (pel->Buffer,
  1561. length,
  1562. FALSE,
  1563. FALSE,
  1564. NULL);
  1565. if (mdl==NULL) {
  1566. status = STATUS_INSUFFICIENT_RESOURCES;
  1567. break;
  1568. }
  1569. IoBuildPartialMdl(
  1570. pel->Mdl,
  1571. mdl,
  1572. pel->Buffer,
  1573. length
  1574. );
  1575. IF_DEBUG (TRANSMIT) {
  1576. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1577. "AfdBuildPacketChain:"
  1578. " tpInfo-%p, partial mdl %p(%lx)\n",
  1579. tpInfo,mdl,mdl->ByteCount));
  1580. }
  1581. }
  1582. }
  1583. else {
  1584. //
  1585. // If we are not in the context of the process that
  1586. // initiated the request, we will need to attach
  1587. // to it to be able to access the memory.
  1588. //
  1589. if (IoGetCurrentProcess ()!=IoGetRequestorProcess (TpIrp)) {
  1590. ASSERT (!attached);
  1591. ASSERT (!KeIsAttachedProcess ());
  1592. ASSERT (IoGetCurrentIrpStackLocation (TpIrp)->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_USE_SYSTEM_THREAD);
  1593. KeAttachProcess (
  1594. PsGetKernelProcess(
  1595. IoGetRequestorProcess (TpIrp)));
  1596. IF_DEBUG (TRANSMIT) {
  1597. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1598. "AfdBuildPacketChain:"
  1599. " tp_info-%p,attached to %p\n",
  1600. tpInfo,PsGetKernelProcess(
  1601. IoGetRequestorProcess (TpIrp))));
  1602. }
  1603. //
  1604. // Set the flag so that we know to detach at exit
  1605. //
  1606. attached = TRUE;
  1607. }
  1608. if (length>AfdTPacketsCopyThreshold) {
  1609. tpInfo->PdNeedsPps = TRUE; // Need to make sure that process
  1610. // memory is there until send completes.
  1611. //
  1612. // Memory block is larger than our large (page)
  1613. // pre-allocated buffer.
  1614. // It is better to probe and lock it
  1615. // First allocate the MDL
  1616. //
  1617. mdl = IoAllocateMdl (pel->Buffer,
  1618. length,
  1619. FALSE,
  1620. TRUE,
  1621. NULL);
  1622. if (mdl==NULL) {
  1623. status = STATUS_INSUFFICIENT_RESOURCES;
  1624. break;
  1625. }
  1626. IF_DEBUG (TRANSMIT) {
  1627. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1628. "AfdBuildPacketChain:"
  1629. " tp_info-%p,big mdl-%p(%p,%lx)\n",
  1630. tpInfo,mdl,pel->Buffer,length));
  1631. }
  1632. //
  1633. // Probe and lock app's memory
  1634. //
  1635. try {
  1636. MmProbeAndLockPages (mdl,
  1637. TpIrp->RequestorMode,
  1638. IoReadAccess
  1639. );
  1640. }
  1641. except (AFD_EXCEPTION_FILTER(&status)) {
  1642. break;
  1643. }
  1644. }
  1645. else if (pel->Flags & TP_COMBINE) {
  1646. //
  1647. // This memory can be combined with the
  1648. // next piece in one buffer.
  1649. //
  1650. if (combinePel==NULL) {
  1651. combinePel = pel;
  1652. combineLen = length;
  1653. }
  1654. else {
  1655. combineLen += length;
  1656. ASSERT (combineLen<=AfdTPacketsCopyThreshold);
  1657. }
  1658. ASSERT (pel->Length==0);
  1659. pel->Length = length;
  1660. IF_DEBUG (TRANSMIT) {
  1661. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1662. "AfdBuildPacketChain:"
  1663. " tp_info-%p,small buffer (%x) to be combined with next\n",
  1664. tpInfo,length));
  1665. }
  1666. continue;
  1667. }
  1668. else {
  1669. //
  1670. // 'Small' memory block, better to copy
  1671. // into pre-allocated (lookaside list) buffer.
  1672. //
  1673. PAFD_BUFFER afdBuffer = NULL;
  1674. PUCHAR buf;
  1675. ULONG bufferLen = length + (combinePel ? combineLen : 0);
  1676. try {
  1677. afdBuffer = AfdGetBufferRaiseOnFailure (
  1678. bufferLen,
  1679. 0,
  1680. endpoint->OwningProcess);
  1681. buf = afdBuffer->Buffer;
  1682. if (combinePel!=NULL) {
  1683. //
  1684. // See if wee need to combine previous elements
  1685. //
  1686. ASSERT (combineLen+length<=AfdTPacketsCopyThreshold);
  1687. ASSERT (combineLen>0);
  1688. while (combinePel!=pel) {
  1689. if ( TpIrp->RequestorMode != KernelMode ) {
  1690. //
  1691. // Probe before copying
  1692. //
  1693. ProbeForRead (combinePel->Buffer,
  1694. combinePel->Length,
  1695. sizeof (UCHAR));
  1696. }
  1697. RtlCopyMemory (buf, combinePel->Buffer, combinePel->Length);
  1698. buf += combinePel->Length;
  1699. #if DBG
  1700. ASSERT (combineLen >= combinePel->Length);
  1701. combineLen -= combinePel->Length;
  1702. #endif
  1703. combinePel++;
  1704. }
  1705. //
  1706. // Reset the local.
  1707. //
  1708. ASSERT (combineLen==0);
  1709. combinePel = NULL;
  1710. }
  1711. if ( TpIrp->RequestorMode != KernelMode ) {
  1712. //
  1713. // Probe before copying
  1714. //
  1715. ProbeForRead (pel->Buffer,
  1716. length,
  1717. sizeof (UCHAR));
  1718. }
  1719. RtlCopyMemory (buf, pel->Buffer, length);
  1720. }
  1721. except (AFD_EXCEPTION_FILTER (&status)) {
  1722. if (afdBuffer!=NULL) {
  1723. AfdReturnBuffer (&afdBuffer->Header,
  1724. endpoint->OwningProcess);
  1725. }
  1726. break;
  1727. }
  1728. //
  1729. // Initialize the buffer structure so that we do not
  1730. // mistake it for file buffer descriptor and insert
  1731. // it into the packet chain
  1732. //
  1733. afdBuffer->FileObject = NULL;
  1734. afdBuffer->Next = NULL;
  1735. (*tpInfo->TailPd) = &afdBuffer->Header;
  1736. tpInfo->TailPd = &(afdBuffer->Next);
  1737. mdl = afdBuffer->Mdl;
  1738. //
  1739. // Adjust MDL length to the amount of data that we
  1740. // actualy sending from the buffer.
  1741. //
  1742. mdl->ByteCount = bufferLen;
  1743. IF_DEBUG (TRANSMIT) {
  1744. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1745. "AfdBuildPacketChain:"
  1746. " tp_info-%p,small buffer-%p(%p,%lx)\n",
  1747. tpInfo,(PVOID)afdBuffer,mdl,length));
  1748. }
  1749. }
  1750. }
  1751. //
  1752. // Insert MDL into the MDL chain
  1753. //
  1754. *(tpInfo->TailMdl) = mdl;
  1755. tpInfo->TailMdl = &(mdl->Next);
  1756. //
  1757. // Advance app's buffer pointer
  1758. //
  1759. ((PUCHAR)pel->Buffer) += length;
  1760. }
  1761. else {
  1762. //
  1763. // This must be a file block
  1764. //
  1765. ASSERT ((pel->Flags & TP_FILE)!=0);
  1766. ASSERT (length!=0);
  1767. if (AFD_USE_CACHE (pel->FileObject)) {
  1768. //
  1769. // Caching file system, get it from cache.
  1770. // We just need a buffer tag to save buffer info
  1771. // so we can return it back to the cache when we
  1772. // are done sending.
  1773. //
  1774. IO_STATUS_BLOCK ioStatus;
  1775. PAFD_BUFFER_TAG afdBufferTag;
  1776. tpInfo->PdNeedsPps = TRUE; // Need to free the MDL back to file
  1777. // system at passive/APC level
  1778. try {
  1779. afdBufferTag = AfdGetBufferTagRaiseOnFailure (
  1780. 0,
  1781. endpoint->OwningProcess);
  1782. }
  1783. except (AFD_EXCEPTION_FILTER (&status)) {
  1784. break;
  1785. }
  1786. //
  1787. // Copy file parameters to the packet descriptor.
  1788. //
  1789. afdBufferTag->FileOffset = pel->FileOffset;
  1790. afdBufferTag->FileObject = pel->FileObject;
  1791. pel->FileOffset.QuadPart += length;
  1792. afdBufferTag->DataLength = length;
  1793. //
  1794. // Set fileMdl to NULL because FsRtlMdlRead attempts to
  1795. // chain the MDLs it returns off the input MDL variable.
  1796. //
  1797. afdBufferTag->Mdl = NULL;
  1798. //
  1799. // Attempt to use the fast path to get file data MDLs
  1800. // directly from the cache.
  1801. //
  1802. if (FsRtlMdlRead(
  1803. afdBufferTag->FileObject,
  1804. &afdBufferTag->FileOffset,
  1805. length,
  1806. 0,
  1807. &afdBufferTag->Mdl,
  1808. &ioStatus
  1809. )) {
  1810. if ( ioStatus.Information < length) {
  1811. //
  1812. // Could not read the whole thing, must be end of file
  1813. //
  1814. status = AfdMdlReadComplete (
  1815. afdBufferTag->FileObject,
  1816. afdBufferTag->Mdl,
  1817. &afdBufferTag->FileOffset);
  1818. if (NT_SUCCESS (status)) {
  1819. AfdReturnBuffer (&afdBufferTag->Header,
  1820. endpoint->OwningProcess);
  1821. }
  1822. else {
  1823. REFERENCE_ENDPOINT (endpoint);
  1824. afdBufferTag->Context = endpoint;
  1825. AfdLRMdlReadComplete (&afdBufferTag->Header);
  1826. }
  1827. status = STATUS_END_OF_FILE;
  1828. break;
  1829. }
  1830. IF_DEBUG (TRANSMIT) {
  1831. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1832. "AfdBuildPacketChain:"
  1833. " tp_info-%p,file tag-%p(%p,%lx:%I64x)\n",
  1834. tpInfo,afdBufferTag,afdBufferTag->Mdl,length,
  1835. pel->FileOffset.QuadPart));
  1836. }
  1837. //
  1838. // Insert the file MDL into the chain
  1839. //
  1840. mdl = *(tpInfo->TailMdl) = afdBufferTag->Mdl;
  1841. while (mdl->Next!=NULL)
  1842. mdl = mdl->Next;
  1843. tpInfo->TailMdl = &mdl->Next;
  1844. //
  1845. // Insert buffer tag into the chain too.
  1846. //
  1847. afdBufferTag->Next = NULL;
  1848. (*tpInfo->TailPd) = &afdBufferTag->Header;
  1849. tpInfo->TailPd = &(afdBufferTag->Next);
  1850. }
  1851. else {
  1852. //
  1853. // File is not in the cache, return STATUS_PENDING
  1854. // so that the Tpacket worker knows to
  1855. // perform MDL read via IRP interface
  1856. //
  1857. if (status==STATUS_SUCCESS) {
  1858. afdBufferTag->PartialMessage = FALSE;
  1859. }
  1860. else {
  1861. ASSERT (status==STATUS_MORE_PROCESSING_REQUIRED);
  1862. afdBufferTag->PartialMessage = TRUE;
  1863. }
  1864. afdBufferTag->Next = NULL;
  1865. *Pd = &afdBufferTag->Header;
  1866. status = STATUS_PENDING;
  1867. break;
  1868. }
  1869. }
  1870. else {
  1871. PAFD_BUFFER afdBuffer;
  1872. //
  1873. // Non-cacheable file system, need buffered read.
  1874. // Get the buffer first.
  1875. //
  1876. try {
  1877. afdBuffer = AfdGetBufferRaiseOnFailure (
  1878. length,
  1879. 0,
  1880. endpoint->OwningProcess);
  1881. }
  1882. except (AFD_EXCEPTION_FILTER (&status)) {
  1883. break;
  1884. }
  1885. //
  1886. // Copy file parameters to the packet descriptor.
  1887. // and return STATUS_PENDING, so that Tpacket worker knows
  1888. // to issue an IRP for buffered read.
  1889. //
  1890. IF_DEBUG (TRANSMIT) {
  1891. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1892. "AfdBuildPacketChain:"
  1893. " tp_info-%p,file buffer-%p(%p,%lx:%I64x)\n",
  1894. tpInfo,(PVOID)afdBuffer,afdBuffer->Mdl,length,
  1895. pel->FileOffset.QuadPart));
  1896. }
  1897. afdBuffer->FileOffset = pel->FileOffset;
  1898. afdBuffer->FileObject = pel->FileObject;
  1899. pel->FileOffset.QuadPart += length;
  1900. afdBuffer->DataLength = length;
  1901. afdBuffer->Mdl->ByteCount = length;
  1902. afdBuffer->Next = NULL;
  1903. if (status==STATUS_SUCCESS) {
  1904. afdBuffer->PartialMessage = FALSE;
  1905. }
  1906. else {
  1907. ASSERT (status==STATUS_MORE_PROCESSING_REQUIRED);
  1908. afdBuffer->PartialMessage = TRUE;
  1909. }
  1910. *Pd = &afdBuffer->Header;
  1911. status = STATUS_PENDING;
  1912. break;
  1913. }
  1914. }
  1915. }
  1916. if (attached) {
  1917. //
  1918. // If we attached to the calling, detach before exiting.
  1919. //
  1920. ASSERT (KeIsAttachedProcess ());
  1921. ASSERT (IoGetCurrentIrpStackLocation (TpIrp)->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_USE_SYSTEM_THREAD);
  1922. KeDetachProcess ();
  1923. IF_DEBUG (TRANSMIT) {
  1924. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1925. "AfdBuildPacketChain:"
  1926. " tp_info-%p, detached\n",
  1927. tpInfo));
  1928. }
  1929. }
  1930. IF_DEBUG (TRANSMIT) {
  1931. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1932. "AfdBuildPacketChain: tp_info-%p,returning %lx\n",
  1933. tpInfo, status));
  1934. }
  1935. ASSERT (combinePel==NULL || !NT_SUCCESS (status));
  1936. return status;
  1937. }
  1938. BOOLEAN
  1939. AfdCleanupPacketChain (
  1940. PIRP TpIrp,
  1941. BOOLEAN BelowDispatch
  1942. )
  1943. /*++
  1944. Routine Description:
  1945. Cleans up (releases all resources in) the packet chain.
  1946. Arguments:
  1947. TpIrp - transmit packet IRP
  1948. BelowDispatch - call is made below DISPATCH_LEVEL, can return MDL to file system
  1949. Return Value:
  1950. TRUE - all packets/MDLs are freed
  1951. FALSE - could not return MDLs to file system (when called at DISPATCH)
  1952. --*/
  1953. {
  1954. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  1955. PAFD_BUFFER_HEADER pd = tpInfo->HeadPd;
  1956. PAFD_ENDPOINT endpoint = IoGetCurrentIrpStackLocation (TpIrp)->FileObject->FsContext;
  1957. ASSERT (tpInfo->HeadMdl!=NULL);
  1958. IF_DEBUG (TRANSMIT) {
  1959. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1960. "AfdCleanupPacketChain: tp_info-%p,mdl-%p,pd-%p\n",
  1961. tpInfo,tpInfo->HeadMdl,tpInfo->HeadPd));
  1962. }
  1963. //
  1964. // Continue while we have any MDL's left
  1965. //
  1966. while (tpInfo->HeadMdl) {
  1967. //
  1968. // Advance to the next MDL
  1969. //
  1970. PMDL mdl;
  1971. mdl = tpInfo->HeadMdl;
  1972. tpInfo->HeadMdl = mdl->Next;
  1973. if (pd!=NULL) {
  1974. //
  1975. // We still have descriptors in the chain to compare against.
  1976. //
  1977. if (mdl==pd->Mdl) {
  1978. //
  1979. // This MDL has associated descriptor - file or buffered memory
  1980. // First remove this descriptor from the chain.
  1981. //
  1982. tpInfo->HeadPd = pd->Next;
  1983. if (pd->FileObject!=NULL && AFD_USE_CACHE (pd->FileObject)) {
  1984. if (BelowDispatch) {
  1985. //
  1986. // Cached file, the descriptor is just a tag with info
  1987. // to return MDL to the cache, do it.
  1988. //
  1989. PAFD_BUFFER_TAG afdBufferTag = CONTAINING_RECORD (pd, AFD_BUFFER_TAG, Header);
  1990. ULONG size = MmGetMdlByteCount (mdl);
  1991. PMDL lastMdl = mdl;
  1992. NTSTATUS status;
  1993. //
  1994. // Scan MDL chain till we find the last one for this file
  1995. // segment.
  1996. //
  1997. IF_DEBUG (TRANSMIT) {
  1998. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1999. "AfdCleanupPacketChain:"
  2000. " tp_info-%p,file tag-%p(%p,%lx:%I64x)\n",
  2001. tpInfo,afdBufferTag,mdl,afdBufferTag->DataLength,
  2002. afdBufferTag->FileOffset.QuadPart));
  2003. }
  2004. while (size<pd->DataLength) {
  2005. size += MmGetMdlByteCount (tpInfo->HeadMdl);
  2006. lastMdl = tpInfo->HeadMdl;
  2007. tpInfo->HeadMdl = tpInfo->HeadMdl->Next;
  2008. }
  2009. lastMdl->Next = NULL;
  2010. ASSERT (size==pd->DataLength);
  2011. //
  2012. // Return the MDL chain to file cache
  2013. //
  2014. status = AfdMdlReadComplete (
  2015. afdBufferTag->FileObject,
  2016. mdl,
  2017. &afdBufferTag->FileOffset);
  2018. if (NT_SUCCESS (status)) {
  2019. //
  2020. // Success free the corresponding buffer tag
  2021. //
  2022. AfdReturnBuffer (pd, endpoint->OwningProcess);
  2023. }
  2024. else {
  2025. //
  2026. // Failure, queue the descriptor to the low resource
  2027. // list to be processed by our global timer when
  2028. // (hopefully) enough memory will be available to do
  2029. // the work.
  2030. // We need to reference the endpoint since buffer tag
  2031. // may have been charged against the process that owns
  2032. // the endpoint.
  2033. //
  2034. REFERENCE_ENDPOINT (endpoint);
  2035. afdBufferTag->Context = endpoint;
  2036. AfdLRMdlReadComplete (&afdBufferTag->Header);
  2037. }
  2038. }
  2039. else {
  2040. //
  2041. // If we are at dispatch, we can't free MDLs to file
  2042. // system, return to the caller.
  2043. //
  2044. tpInfo->HeadPd = pd;
  2045. tpInfo->HeadMdl = mdl;
  2046. return FALSE;
  2047. }
  2048. }
  2049. else {
  2050. //
  2051. // Buffer with either file or memory data, just return
  2052. // it back to the pool.
  2053. //
  2054. PAFD_BUFFER afdBuffer = CONTAINING_RECORD (pd, AFD_BUFFER, Header);
  2055. IF_DEBUG (TRANSMIT) {
  2056. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2057. "AfdCleanupPacketChain:"
  2058. " tp_info-%p,file buffer-%p(%p,%lx:%I64x)\n",
  2059. tpInfo,(PVOID)afdBuffer,mdl,afdBuffer->DataLength,
  2060. afdBuffer->FileOffset.QuadPart));
  2061. }
  2062. afdBuffer->Mdl->Next = NULL;
  2063. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  2064. AfdReturnBuffer (pd, endpoint->OwningProcess);
  2065. }
  2066. //
  2067. // Move to the next descriptor in the chain.
  2068. //
  2069. pd = tpInfo->HeadPd;
  2070. continue;
  2071. }
  2072. }
  2073. //
  2074. // Stand-alone MDL with memory data
  2075. // Just unlock the pages if they were locked and return it.
  2076. // We never lock memory in partial MDLs, only in their source MDL
  2077. //
  2078. IF_DEBUG (TRANSMIT) {
  2079. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2080. "AfdCleanupPacketChain: tp_info-%p, mdl-%p(%p,%x,%x)\n",
  2081. tpInfo,mdl,
  2082. MmGetMdlVirtualAddress(mdl),
  2083. MmGetMdlByteCount (mdl),
  2084. mdl->MdlFlags));
  2085. }
  2086. mdl->Next = NULL;
  2087. if (mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) {
  2088. ASSERT (mdl->MappedSystemVa==(PVOID)tpInfo);
  2089. ASSERT (mdl->ByteCount==0);
  2090. mdl->ByteCount = 1;
  2091. }
  2092. else if (mdl->MdlFlags & MDL_PAGES_LOCKED &&
  2093. !(mdl->MdlFlags & MDL_PARTIAL)) {
  2094. MmUnlockPages (mdl);
  2095. }
  2096. IoFreeMdl (mdl);
  2097. }
  2098. ASSERT (tpInfo->TailMdl == &tpInfo->HeadMdl);
  2099. ASSERT (tpInfo->HeadPd == NULL);
  2100. ASSERT (tpInfo->TailPd == &tpInfo->HeadPd);
  2101. return TRUE;
  2102. }
  2103. NTSTATUS
  2104. AfdTPacketsSend (
  2105. PIRP TpIrp,
  2106. USHORT SendIrp
  2107. )
  2108. /*++
  2109. Routine Description:
  2110. Takes the packets chain of the TpInfo and sends it.
  2111. Places back the chain sent before, so it can be freed.
  2112. If requested by the app and the last element is being sent,
  2113. initiates the disconnect.
  2114. Arguments:
  2115. TpIrp - transmit packet irp
  2116. SendIrp - index of the IRP to use for this send.
  2117. Return Value:
  2118. STATUS_SUCCESS - send was queued to the transport OK
  2119. other - send failed
  2120. --*/
  2121. {
  2122. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  2123. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (TpIrp);
  2124. PMDL tempMdl=NULL;
  2125. PAFD_BUFFER_HEADER tempPd=NULL;
  2126. NTSTATUS status = STATUS_SUCCESS;
  2127. PIRP irp, sendIrp=NULL;
  2128. PIO_COMPLETION_ROUTINE sendCompletion = AfdRestartTPacketsSend;
  2129. ASSERT (AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED);
  2130. irp = tpInfo->SendIrp[SendIrp];
  2131. //
  2132. // See if we can use IRP built into the AFD buffer.
  2133. // We do this for last series of the packets only so
  2134. // we can effectively buffer the data and complete the
  2135. // IRP early.
  2136. //
  2137. if (tpInfo->RemainingPkts!=MAXULONG) {
  2138. tpInfo->RemainingPkts -= 1;
  2139. //
  2140. // The conditions are:
  2141. // - number of remaining packets is less then total
  2142. // outstanding IRPs we can have
  2143. // - the packet does not need post-processing at below
  2144. // DPC level and/or in context of the thread/process
  2145. // - we actually have afd buffer to borrow the IRP.
  2146. //
  2147. if (tpInfo->RemainingPkts < (ULONG)tpInfo->NumSendIrps &&
  2148. !tpInfo->PdNeedsPps &&
  2149. tpInfo->HeadPd!=NULL) {
  2150. PAFD_BUFFER afdBuffer = CONTAINING_RECORD (tpInfo->HeadPd,
  2151. AFD_BUFFER,
  2152. Header);
  2153. ASSERT (afdBuffer->BufferLength!=0);
  2154. ASSERT (afdBuffer->Irp!=NULL);
  2155. sendIrp = afdBuffer->Irp;
  2156. afdBuffer->Context = irpSp->FileObject->FsContext;
  2157. sendCompletion = AfdRestartTPDetachedSend;
  2158. //
  2159. // There will be no completion flag reset - we do not have
  2160. // to wait for this one.
  2161. //
  2162. AFD_CLEAR_TP_FLAGS (TpIrp, AFD_TP_SEND_COMP_PENDING(SendIrp));
  2163. }
  2164. }
  2165. if (irp!=NULL) {
  2166. //
  2167. // Get the old data from the IRP.
  2168. //
  2169. ASSERT (irp->Overlay.AsynchronousParameters.UserApcRoutine==(PVOID)SendIrp);
  2170. tempPd = irp->Overlay.AsynchronousParameters.UserApcContext;
  2171. tempMdl = irp->MdlAddress;
  2172. if (sendIrp==NULL) {
  2173. //
  2174. // No special send IRP, the data will be reset with
  2175. // data to be sent
  2176. //
  2177. sendIrp = irp;
  2178. }
  2179. else {
  2180. //
  2181. // We are not going to use this IRP, reset data to NULL.
  2182. //
  2183. irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
  2184. irp->MdlAddress = NULL;
  2185. }
  2186. }
  2187. else if (sendIrp==NULL) {
  2188. //
  2189. // We need to allocate an IRP.
  2190. //
  2191. ASSERT (SendIrp>=AFD_TP_MIN_SEND_IRPS);
  2192. tpInfo->SendIrp[SendIrp] = IoAllocateIrp (tpInfo->TdiDeviceObject->StackSize, TRUE);
  2193. if (tpInfo->SendIrp[SendIrp]==NULL) {
  2194. status = STATUS_INSUFFICIENT_RESOURCES;
  2195. AfdAbortTPackets (TpIrp, status);
  2196. return status;
  2197. }
  2198. sendIrp = irp = tpInfo->SendIrp[SendIrp];
  2199. irp->Overlay.AsynchronousParameters.UserApcRoutine=(PVOID)SendIrp;
  2200. }
  2201. //
  2202. // Exchange the packet and MDL chains between send IRP and
  2203. // the tpInfo structure
  2204. //
  2205. sendIrp->Overlay.AsynchronousParameters.UserApcContext = tpInfo->HeadPd;
  2206. tpInfo->HeadPd = tempPd;
  2207. tpInfo->TailPd = &tpInfo->HeadPd;
  2208. //
  2209. // Build send IRP. Used combined send and disconnect if necessary
  2210. // and possible.
  2211. //
  2212. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  2213. if ((irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT) &&
  2214. (tpInfo->PdLength>0) && // Must be sending something or no S&D
  2215. (tpInfo->NextElement>=tpInfo->ElementCount) &&
  2216. AfdTPacketsEnableSendAndDisconnect (TpIrp)) {
  2217. AFD_SET_TP_FLAGS (TpIrp, AFD_TP_SEND_AND_DISCONNECT);
  2218. TdiBuildSend (sendIrp,
  2219. tpInfo->TdiDeviceObject,
  2220. tpInfo->TdiFileObject,
  2221. sendCompletion,
  2222. TpIrp,
  2223. tpInfo->HeadMdl,
  2224. TDI_SEND_AND_DISCONNECT,
  2225. tpInfo->PdLength
  2226. );
  2227. }
  2228. else {
  2229. TdiBuildSend (sendIrp,
  2230. tpInfo->TdiDeviceObject,
  2231. tpInfo->TdiFileObject,
  2232. sendCompletion,
  2233. TpIrp,
  2234. tpInfo->HeadMdl,
  2235. 0,
  2236. tpInfo->PdLength
  2237. );
  2238. }
  2239. #else //TDI_SERVICE_SEND_AND_DISCONNECT
  2240. TdiBuildSend (sendIrp,
  2241. tpInfo->TdiDeviceObject,
  2242. tpInfo->TdiFileObject,
  2243. sendCompletion,
  2244. TpIrp,
  2245. tpInfo->HeadMdl,
  2246. 0,
  2247. tpInfo->PdLength
  2248. );
  2249. #endif //TDI_SERVICE_SEND_AND_DISCONNECT
  2250. IF_DEBUG (TRANSMIT) {
  2251. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2252. "AfdTPacketsSend: tpInfo-%p, sending Irp: %p\n",
  2253. tpInfo, irp));
  2254. }
  2255. if (sendCompletion==AfdRestartTPacketsSend) {
  2256. //
  2257. // Reference the tpInfo structure so it does not go away
  2258. // till send IRP completes and pass the IRP to the transport.
  2259. //
  2260. REFERENCE_TPACKETS (TpIrp);
  2261. IoCallDriver (tpInfo->TdiDeviceObject, sendIrp);
  2262. }
  2263. else {
  2264. //
  2265. // No need to reference as we are not going to wait for
  2266. // completion.
  2267. //
  2268. status = IoCallDriver (tpInfo->TdiDeviceObject, sendIrp);
  2269. if (NT_SUCCESS (status)) {
  2270. //
  2271. // Change STATUS_PENDING to success not to confuse the caller
  2272. // and add byte count under assumption of success (if it fails
  2273. // later, connection will be dropped and we don't guarantee
  2274. // anything for datagrams anyway).
  2275. //
  2276. status = STATUS_SUCCESS;
  2277. #ifdef _WIN64
  2278. InterlockedExchangeAdd64 (
  2279. &TpIrp->IoStatus.Information,
  2280. tpInfo->PdLength
  2281. );
  2282. #else //_WIN64
  2283. InterlockedExchangeAdd (
  2284. &TpIrp->IoStatus.Information,
  2285. tpInfo->PdLength);
  2286. #endif //_WIN64
  2287. }
  2288. else {
  2289. //
  2290. // If send fails, we'll have to abort here since completion routine
  2291. // will not have access to the TpIrp
  2292. //
  2293. IF_DEBUG (TRANSMIT) {
  2294. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2295. "AfdTPacketsSend: tpInfo-%p, detached send failed: %lx\n",
  2296. tpInfo, status));
  2297. }
  2298. AfdAbortTPackets (TpIrp, status);
  2299. }
  2300. }
  2301. //
  2302. // Setup the chain in the tpInfo so it can be freed.
  2303. //
  2304. tpInfo->HeadMdl = tempMdl;
  2305. tpInfo->TailMdl = &tpInfo->HeadMdl;
  2306. tpInfo->PdLength = 0;
  2307. tpInfo->PdNeedsPps = FALSE;
  2308. if (tpInfo->NextElement>=tpInfo->ElementCount) {
  2309. PAFD_ENDPOINT endpoint = irpSp->FileObject->FsContext;
  2310. if (!(irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT)) {
  2311. AfdStartNextTPacketsIrp (endpoint, TpIrp);
  2312. }
  2313. else
  2314. //
  2315. // If necessary and not using combined S&D,
  2316. // sumbit disconnect IRP to the transport
  2317. //
  2318. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  2319. if (!(AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_SEND_AND_DISCONNECT))
  2320. #endif // TDI_SERVICE_SEND_AND_DISCONNECT
  2321. {
  2322. ASSERT (endpoint->Type==AfdBlockTypeVcConnecting);
  2323. ASSERT (endpoint->Common.VcConnecting.Connection!=NULL);
  2324. status = AfdBeginDisconnect(
  2325. endpoint,
  2326. NULL,
  2327. NULL
  2328. );
  2329. if (NT_SUCCESS (status)) {
  2330. IF_DEBUG (TRANSMIT) {
  2331. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2332. "AfdTPacketsSend: Initiated disconnect, tpInfo-%p,status-%lx\n",
  2333. tpInfo, status));
  2334. }
  2335. //
  2336. // Change STATUS_PENDING to success not to confuse the caller.
  2337. //
  2338. status = STATUS_SUCCESS;
  2339. }
  2340. else {
  2341. //
  2342. // If disconnect fails, we'll have to abort
  2343. //
  2344. IF_DEBUG (TRANSMIT) {
  2345. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2346. "AfdTPacketsSend: tpInfo-%p, begin discon failed: %lx\n",
  2347. tpInfo, status));
  2348. }
  2349. AfdAbortTPackets (TpIrp, status);
  2350. }
  2351. }
  2352. }
  2353. //
  2354. // Set the flag indicating to the completion routine that we are done
  2355. //
  2356. AFD_CLEAR_TP_FLAGS (TpIrp, AFD_TP_SEND_CALL_PENDING(SendIrp));
  2357. UPDATE_TPACKETS2 (TpIrp, "Submitted SendIrp: %ld", SendIrp);
  2358. return status;
  2359. }
  2360. NTSTATUS
  2361. AfdRestartTPacketsSend (
  2362. IN PDEVICE_OBJECT DeviceObject,
  2363. IN PIRP Irp,
  2364. IN PVOID Context
  2365. )
  2366. /*++
  2367. Routine Description:
  2368. Completion routine for TPackets send.
  2369. Does another send if packet is ready or schedules worker
  2370. to do the same.
  2371. Arguments:
  2372. DeviceObject - AfdDeviceObject
  2373. Irp - send IRP being completed
  2374. Context - TpIrp
  2375. Return Value:
  2376. STATUS_MORE_PROCESSING_REQUIRED - tell IO subsystem to stop
  2377. processing the IRP (it is handled internally).
  2378. --*/
  2379. {
  2380. PIRP tpIrp;
  2381. PAFD_TPACKETS_INFO_INTERNAL tpInfo;
  2382. PAFD_ENDPOINT endpoint;
  2383. USHORT sendIrp;
  2384. tpIrp = Context;
  2385. tpInfo = tpIrp->AssociatedIrp.SystemBuffer;
  2386. endpoint = IoGetCurrentIrpStackLocation (tpIrp)->FileObject->FsContext;
  2387. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2388. //
  2389. // Figure out which IRP is being completed.
  2390. //
  2391. sendIrp = (USHORT)Irp->Overlay.AsynchronousParameters.UserApcRoutine;
  2392. ASSERT (tpInfo->SendIrp[sendIrp]==Irp);
  2393. IF_DEBUG (TRANSMIT) {
  2394. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2395. "AfdRestartTPacketsSend: tp_info-%p,Irp-%p,status-%lx\n",
  2396. tpInfo,
  2397. Irp,
  2398. Irp->IoStatus.Status
  2399. ));
  2400. }
  2401. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  2402. LONG stateFlags, newStateFlags;
  2403. BOOLEAN needWorker;
  2404. UPDATE_TPACKETS2 (tpIrp, "Send completed with 0x%lX bytes",
  2405. (ULONG)Irp->IoStatus.Information);
  2406. //
  2407. // Successfull completion, update transfer count.
  2408. // We don't hold the spinlock, so we need to use interlocked operation.
  2409. // Wish we have a common one for both 64 and 32 bit platforms.
  2410. //
  2411. #ifdef _WIN64
  2412. InterlockedExchangeAdd64 (
  2413. &tpIrp->IoStatus.Information,
  2414. Irp->IoStatus.Information);
  2415. #else //_WIN64
  2416. InterlockedExchangeAdd (&tpIrp->IoStatus.Information,
  2417. Irp->IoStatus.Information);
  2418. #endif //_WIN64
  2419. //
  2420. // See if dispatch routine completed already and
  2421. // the request is not aborted or worker is aready running
  2422. //
  2423. do {
  2424. ULONG sendMask;
  2425. newStateFlags = stateFlags = AFD_GET_TPIC(tpIrp)->StateFlags;
  2426. if ( (newStateFlags & (AFD_TP_ABORT_PENDING |
  2427. AFD_TP_WORKER_SCHEDULED |
  2428. AFD_TP_SEND_CALL_PENDING(sendIrp))) ||
  2429. ((sendMask = (newStateFlags & AFD_TP_SEND_MASK)) &
  2430. ( (sendMask>>2) |
  2431. (sendMask<<(AFD_TP_MAX_SEND_IRPS*2-2)) ) )
  2432. ) {
  2433. //
  2434. // Can't continue, just clear completion flag
  2435. //
  2436. newStateFlags &= ~AFD_TP_SEND_COMP_PENDING(sendIrp);
  2437. needWorker = FALSE;
  2438. }
  2439. else {
  2440. //
  2441. // Take control over worker scheduling and
  2442. // mark IRP as busy.
  2443. //
  2444. needWorker = TRUE;
  2445. newStateFlags |= AFD_TP_WORKER_SCHEDULED;
  2446. if (tpInfo->HeadMdl!=NULL) {
  2447. newStateFlags |= AFD_TP_SEND_CALL_PENDING(sendIrp);
  2448. }
  2449. else {
  2450. newStateFlags &= ~AFD_TP_SEND_COMP_PENDING(sendIrp);
  2451. }
  2452. }
  2453. }
  2454. while (InterlockedCompareExchange (
  2455. (PLONG)&AFD_GET_TPIC(tpIrp)->StateFlags,
  2456. newStateFlags,
  2457. stateFlags)!=stateFlags);
  2458. if (needWorker) {
  2459. //
  2460. // We can do processing here, see if there is something to send
  2461. //
  2462. if (tpInfo->HeadMdl) {
  2463. //
  2464. // Yes, do it
  2465. //
  2466. AfdTPacketsSend (tpIrp, sendIrp);
  2467. }
  2468. //
  2469. // Start worker to prepare new stuff/free what we sent before.
  2470. // We transfer the reference we added when we queued the request
  2471. // to the worker.
  2472. //
  2473. AfdStartTPacketsWorker (AfdTPacketsWorker, tpIrp);
  2474. return STATUS_MORE_PROCESSING_REQUIRED;
  2475. }
  2476. else {
  2477. //
  2478. // Worker was already running or request aborted or dispatch
  2479. // routine not completed yet.
  2480. //
  2481. }
  2482. }
  2483. else {
  2484. //
  2485. // Failure, abort the request even if dispatch did not complete.
  2486. // We do not know if dispatch routine is going to return error status,
  2487. // it may just return STATUS_PENDING and we then loose the error code.
  2488. // Double abort is harmless.
  2489. //
  2490. AFD_CLEAR_TP_FLAGS (tpIrp, AFD_TP_SEND_COMP_PENDING(sendIrp));
  2491. AfdAbortTPackets (tpIrp, Irp->IoStatus.Status);
  2492. }
  2493. //
  2494. // Remove the reference we added when we queued the request.
  2495. //
  2496. DEREFERENCE_TPACKETS (tpIrp);
  2497. return STATUS_MORE_PROCESSING_REQUIRED;
  2498. }
  2499. NTSTATUS
  2500. AfdRestartTPDetachedSend (
  2501. IN PDEVICE_OBJECT DeviceObject,
  2502. IN PIRP Irp,
  2503. IN PVOID Context
  2504. )
  2505. /*++
  2506. Routine Description:
  2507. Completion routine for detached TPackets send.
  2508. Just frees the buffers.
  2509. Arguments:
  2510. DeviceObject - AfdDeviceObject
  2511. Irp - send IRP being completed
  2512. Context - Ignore (TpIrp is stored for debugging purposes only).
  2513. Return Value:
  2514. STATUS_MORE_PROCESSING_REQUIRED - tell IO subsystem to stop
  2515. processing the IRP (it is handled internally).
  2516. --*/
  2517. {
  2518. PAFD_BUFFER afdBuffer = Irp->Overlay.AsynchronousParameters.UserApcContext;
  2519. PAFD_ENDPOINT endpoint = afdBuffer->Context;
  2520. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2521. IF_DEBUG (TRANSMIT) {
  2522. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2523. "AfdRestartTPDetachedSend: Irp-%p,status-%lx\n",
  2524. Irp,
  2525. Irp->IoStatus.Status
  2526. ));
  2527. }
  2528. do {
  2529. PAFD_BUFFER tempBuffer = afdBuffer;
  2530. afdBuffer = CONTAINING_RECORD (afdBuffer->Next, AFD_BUFFER, Header);
  2531. tempBuffer->Next = NULL;
  2532. tempBuffer->Mdl->Next = NULL;
  2533. tempBuffer->Mdl->ByteCount = tempBuffer->BufferLength;
  2534. AfdReturnBuffer (&tempBuffer->Header, endpoint->OwningProcess);
  2535. }
  2536. while (afdBuffer!=NULL);
  2537. return STATUS_MORE_PROCESSING_REQUIRED;
  2538. }
  2539. USHORT
  2540. AfdTPacketsFindSendIrp (
  2541. PIRP TpIrp
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. Finds the send IRP that is not currently in use and marks
  2546. it as busy
  2547. Arguments:
  2548. TpIrp - Transmit packets Irp
  2549. Return Value:
  2550. 0-based index of send irp or TpInfo->NumSendIrps if all IRPs are i use
  2551. --*/
  2552. {
  2553. LONG stateFlags, newStateFlags;
  2554. USHORT sendIrp;
  2555. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  2556. ASSERT( AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED );
  2557. do {
  2558. newStateFlags = stateFlags = AFD_GET_TPIC(TpIrp)->StateFlags;
  2559. if (newStateFlags & AFD_TP_ABORT_PENDING) {
  2560. //
  2561. // Abort is in progress, bail
  2562. //
  2563. sendIrp = tpInfo->NumSendIrps;
  2564. break;
  2565. }
  2566. //
  2567. // See if any send IRP is not in use
  2568. //
  2569. for (sendIrp=0; sendIrp<tpInfo->NumSendIrps; sendIrp++) {
  2570. if ((newStateFlags & AFD_TP_SEND_BUSY(sendIrp))==0) {
  2571. break;
  2572. }
  2573. }
  2574. if (sendIrp!=tpInfo->NumSendIrps) {
  2575. //
  2576. // Found send IRP, mark it as busy
  2577. //
  2578. newStateFlags |= AFD_TP_SEND_BUSY(sendIrp);
  2579. }
  2580. else {
  2581. //
  2582. // No send IRPs, suspend the worker.
  2583. //
  2584. newStateFlags &= (~AFD_TP_WORKER_SCHEDULED);
  2585. }
  2586. }
  2587. while (InterlockedCompareExchange (
  2588. (PLONG)&AFD_GET_TPIC(TpIrp)->StateFlags,
  2589. newStateFlags,
  2590. stateFlags)!=stateFlags);
  2591. return sendIrp;
  2592. }
  2593. NTSTATUS
  2594. AfdTPacketsMdlRead (
  2595. PIRP TpIrp,
  2596. PAFD_BUFFER_HEADER Pd
  2597. )
  2598. /*++
  2599. Routine Description:
  2600. Performs IRP based MDL read (invoked when cache read fails).
  2601. Arguments:
  2602. TpIrp - transmit packet irp
  2603. Pd - descriptor with file parameters for the read
  2604. Return Value:
  2605. STATUS_SUCCESS - read was completed in-line
  2606. STATUS_PENDING - read was queued to file system driver,
  2607. will complete lated
  2608. other - read failed
  2609. --*/
  2610. {
  2611. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  2612. PDEVICE_OBJECT deviceObject;
  2613. PIRP irp;
  2614. PIO_STACK_LOCATION irpSp;
  2615. ASSERT( AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED );
  2616. //
  2617. // Find the device object and allocate IRP of appropriate size
  2618. // if current one does not fit or is not available at all.
  2619. //
  2620. deviceObject = IoGetRelatedDeviceObject (Pd->FileObject);
  2621. if ((tpInfo->ReadIrp==NULL) ||
  2622. (tpInfo->ReadIrp->StackCount<deviceObject->StackSize)) {
  2623. if (tpInfo->ReadIrp!=NULL) {
  2624. IoFreeIrp (tpInfo->ReadIrp);
  2625. }
  2626. tpInfo->ReadIrp = IoAllocateIrp (deviceObject->StackSize, FALSE);
  2627. if (tpInfo->ReadIrp==NULL) {
  2628. PAFD_ENDPOINT endpoint;
  2629. endpoint = IoGetCurrentIrpStackLocation (TpIrp)->FileObject->FsContext;
  2630. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2631. AfdReturnBuffer (Pd, endpoint->OwningProcess);
  2632. return STATUS_INSUFFICIENT_RESOURCES;
  2633. }
  2634. }
  2635. //
  2636. // Mark IRP as busy and set it up
  2637. //
  2638. AFD_SET_TP_FLAGS (TpIrp, AFD_TP_READ_BUSY);
  2639. irp = tpInfo->ReadIrp;
  2640. irp->MdlAddress = NULL;
  2641. //
  2642. // Set the synchronous flag in the IRP to tell the file system
  2643. // that we are aware of the fact that this IRP will be completed
  2644. // synchronously. This means that we must supply our own thread
  2645. // for the operation and that the disk read will occur
  2646. // synchronously in this thread if the data is not cached.
  2647. //
  2648. irp->Flags |= IRP_SYNCHRONOUS_API;
  2649. irp->Overlay.AsynchronousParameters.UserApcContext = Pd;
  2650. //
  2651. // Set current thread for IoSetHardErrorOrVerifyDevice.
  2652. //
  2653. irp->Tail.Overlay.Thread = PsGetCurrentThread ();
  2654. irpSp = IoGetNextIrpStackLocation( irp );
  2655. irpSp->MajorFunction = IRP_MJ_READ;
  2656. irpSp->MinorFunction = IRP_MN_MDL;
  2657. irpSp->FileObject = Pd->FileObject;
  2658. irpSp->DeviceObject = deviceObject;
  2659. IoSetCompletionRoutine(
  2660. irp,
  2661. AfdRestartTPacketsMdlRead,
  2662. TpIrp,
  2663. TRUE,
  2664. TRUE,
  2665. TRUE
  2666. );
  2667. ASSERT( irpSp->Parameters.Read.Key == 0 );
  2668. //
  2669. // Finish building the read IRP.
  2670. //
  2671. irpSp->Parameters.Read.Length = Pd->DataLength;
  2672. irpSp->Parameters.Read.ByteOffset = Pd->FileOffset;
  2673. REFERENCE_TPACKETS (TpIrp);
  2674. IF_DEBUG (TRANSMIT) {
  2675. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2676. "AfdTPacketsMdlRead: tp_info-%p,Irp-%p,file-%pd,offset-%I64x,length-%lx\n",
  2677. tpInfo,
  2678. irp,
  2679. Pd->FileObject,
  2680. Pd->FileOffset.QuadPart,
  2681. Pd->DataLength));
  2682. }
  2683. IoCallDriver (deviceObject, irp);
  2684. if (((AFD_CLEAR_TP_FLAGS (TpIrp, AFD_TP_READ_CALL_PENDING)
  2685. & (AFD_TP_READ_COMP_PENDING|AFD_TP_ABORT_PENDING))==0) &&
  2686. NT_SUCCESS (irp->IoStatus.Status) &&
  2687. AfdTPacketsContinueAfterRead (TpIrp)) {
  2688. //
  2689. // Read completed successfully inline and post-processing was successfull,
  2690. // tell the worker to go on.
  2691. //
  2692. UPDATE_TPACKETS2 (TpIrp, "MdlRead completed inline with 0x%lX bytes",
  2693. (ULONG)irp->IoStatus.Information);
  2694. return STATUS_SUCCESS;
  2695. }
  2696. else {
  2697. //
  2698. // Read has not completed yet or post processing failed,
  2699. // worker should bail and we will continue when read completes
  2700. // or in final completion routine (AfdCompleteTPackets).
  2701. //
  2702. return STATUS_PENDING;
  2703. }
  2704. }
  2705. NTSTATUS
  2706. AfdRestartTPacketsMdlRead (
  2707. IN PDEVICE_OBJECT DeviceObject,
  2708. IN PIRP Irp,
  2709. IN PVOID Context
  2710. )
  2711. /*++
  2712. Routine Description:
  2713. Completion routine for IRP based MDL read.
  2714. Does another send if packet is ready or schedules worker
  2715. to do the same.
  2716. Arguments:
  2717. DeviceObject - AfdDeviceObject
  2718. Irp - read IRP being completed
  2719. Context - TpIrp
  2720. Return Value:
  2721. STATUS_MORE_PROCESSING_REQUIRED - tell IO subsystem to stop
  2722. processing the IRP (it is handled internally).
  2723. --*/
  2724. {
  2725. PIRP tpIrp = Context;
  2726. PAFD_TPACKETS_INFO_INTERNAL tpInfo = tpIrp->AssociatedIrp.SystemBuffer;
  2727. PAFD_ENDPOINT endpoint;
  2728. PAFD_BUFFER_HEADER pd;
  2729. endpoint = IoGetCurrentIrpStackLocation (tpIrp)->FileObject->FsContext;
  2730. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  2731. ASSERT (AFD_GET_TPIC(tpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED);
  2732. ASSERT (tpInfo->ReadIrp == Irp);
  2733. pd = Irp->Overlay.AsynchronousParameters.UserApcContext;
  2734. IF_DEBUG (TRANSMIT) {
  2735. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2736. "AfdRestartTPacketsMdlRead:"
  2737. " tp_info-%p,Irp-%p,status-%lx,length-%p,mdl-%p\n",
  2738. tpInfo,
  2739. Irp,
  2740. Irp->IoStatus.Status,
  2741. Irp->IoStatus.Information,
  2742. Irp->MdlAddress));
  2743. }
  2744. //
  2745. // Insert MDL into the current chain.
  2746. //
  2747. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  2748. PMDL mdl = *(tpInfo->TailMdl) = Irp->MdlAddress;
  2749. while (mdl->Next!=NULL)
  2750. mdl = mdl->Next;
  2751. tpInfo->TailMdl = &mdl->Next;
  2752. pd->Mdl = Irp->MdlAddress;
  2753. //
  2754. // If FS driver hits EOF, it will still return
  2755. // success to us and we need to handle this case.
  2756. //
  2757. if (pd->DataLength==Irp->IoStatus.Information) {
  2758. (*tpInfo->TailPd) = pd;
  2759. tpInfo->TailPd = &(pd->Next);
  2760. Irp->MdlAddress = NULL;
  2761. if (((AFD_CLEAR_TP_FLAGS (tpIrp, AFD_TP_READ_COMP_PENDING)
  2762. & (AFD_TP_READ_CALL_PENDING|AFD_TP_ABORT_PENDING))==0) &&
  2763. AfdTPacketsContinueAfterRead (tpIrp)) {
  2764. //
  2765. // Read dispatch has already returned and post-processing
  2766. // was successfull, schedule the worker to continue processing
  2767. // We transfer the reference that we added when we queued the
  2768. // read to the worker.
  2769. //
  2770. UPDATE_TPACKETS2 (tpIrp, "MdlRead completed in restart with 0x%lX bytes",
  2771. (ULONG)Irp->IoStatus.Information);
  2772. AfdStartTPacketsWorker (AfdTPacketsWorker, tpIrp);
  2773. }
  2774. else {
  2775. DEREFERENCE_TPACKETS (tpIrp);
  2776. }
  2777. return STATUS_MORE_PROCESSING_REQUIRED;
  2778. }
  2779. //
  2780. // FS driver read less than we expected.
  2781. // We must have hit end of file.
  2782. // Save the real packet length so we can cleanup correctly and
  2783. // force abort with STATUS_END_OF_FILE.
  2784. //
  2785. Irp->IoStatus.Status = STATUS_END_OF_FILE;
  2786. pd->DataLength = (ULONG)Irp->IoStatus.Information;
  2787. }
  2788. else {
  2789. ASSERT (Irp->MdlAddress == NULL);
  2790. }
  2791. AFD_CLEAR_TP_FLAGS (tpIrp, AFD_TP_READ_COMP_PENDING);
  2792. AfdAbortTPackets (tpIrp, Irp->IoStatus.Status);
  2793. if (pd->Mdl==NULL) {
  2794. //
  2795. // No MDL was returned by the file system.
  2796. // We can free the packed descriptor immediately.
  2797. //
  2798. AfdReturnBuffer (pd, endpoint->OwningProcess);
  2799. }
  2800. else {
  2801. //
  2802. // File system did return MDL to us.
  2803. // Save the descriptor so the MDL can be
  2804. // properly returned back to the file system
  2805. // by the cleanup routine.
  2806. //
  2807. (*tpInfo->TailPd) = pd;
  2808. tpInfo->TailPd = &(pd->Next);
  2809. }
  2810. DEREFERENCE_TPACKETS (tpIrp);
  2811. return STATUS_MORE_PROCESSING_REQUIRED;
  2812. }
  2813. NTSTATUS
  2814. AfdMdlReadComplete (
  2815. PFILE_OBJECT FileObject,
  2816. PMDL FileMdl,
  2817. PLARGE_INTEGER FileOffset
  2818. )
  2819. /*++
  2820. Routine Description:
  2821. Returns MDL to the file system / cache manager
  2822. Arguments:
  2823. FileObject - file object from which MDL comes
  2824. FileMdl - MDL itself
  2825. FileOffset - offset in the file where MDL data begins
  2826. Return Value:
  2827. STATUS_SUCCESS - operation completed immediately
  2828. STATUS_PENDING - request is sumbitted to file system driver
  2829. other - operation failed.
  2830. Notes:
  2831. --*/
  2832. {
  2833. PIRP irp;
  2834. PIO_STACK_LOCATION irpSp;
  2835. PDEVICE_OBJECT deviceObject;
  2836. ASSERT (KeGetCurrentIrql()<=APC_LEVEL);
  2837. if( FsRtlMdlReadComplete (
  2838. FileObject,
  2839. FileMdl) ) {
  2840. return STATUS_SUCCESS;
  2841. }
  2842. //
  2843. // Fast path failed, so create a new IRP.
  2844. //
  2845. deviceObject = IoGetRelatedDeviceObject (FileObject);
  2846. irp = IoAllocateIrp(
  2847. deviceObject->StackSize,
  2848. FALSE
  2849. );
  2850. if( irp == NULL ) {
  2851. return STATUS_INSUFFICIENT_RESOURCES;
  2852. }
  2853. //
  2854. // Setup the IRP.
  2855. //
  2856. irpSp = IoGetNextIrpStackLocation( irp );
  2857. irp->MdlAddress = FileMdl;
  2858. irpSp->MajorFunction = IRP_MJ_READ;
  2859. irpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE;
  2860. irpSp->Parameters.Read.Length = 0;
  2861. while (FileMdl!=NULL) {
  2862. irpSp->Parameters.Read.Length += FileMdl->ByteCount;
  2863. FileMdl = FileMdl->Next;
  2864. }
  2865. irpSp->Parameters.Read.ByteOffset = *FileOffset;
  2866. irpSp->Parameters.Read.Key = 0;
  2867. //
  2868. // Reference file object so it does not go away till this
  2869. // IRP completes
  2870. //
  2871. ObReferenceObject (FileObject);
  2872. AfdRecordFileRef ();
  2873. irpSp->FileObject = FileObject;
  2874. irpSp->DeviceObject = deviceObject;
  2875. //
  2876. // Submit the IRP
  2877. //
  2878. IoSetCompletionRoutine(
  2879. irp,
  2880. AfdRestartMdlReadComplete,
  2881. FileObject,
  2882. TRUE,
  2883. TRUE,
  2884. TRUE
  2885. );
  2886. IF_DEBUG (TRANSMIT) {
  2887. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2888. "AfdMdlReadComplete: file-%p,Irp-%p,offset-%I64x\n",
  2889. FileObject,
  2890. irp,
  2891. FileOffset->QuadPart));
  2892. }
  2893. IoCallDriver (deviceObject, irp);
  2894. return STATUS_PENDING;
  2895. }
  2896. NTSTATUS
  2897. AfdRestartMdlReadComplete (
  2898. IN PDEVICE_OBJECT DeviceObject,
  2899. IN PIRP Irp,
  2900. IN PVOID Context
  2901. )
  2902. /*++
  2903. Routine Description:
  2904. Completion routine for IRPs issued by AfdMdlReadComplete. The only
  2905. purpose of this completion routine is to free the IRPs created by
  2906. AfdMdlReadComplete() and release file object reference.
  2907. Arguments:
  2908. DeviceObject - Unused.
  2909. Irp - The completed IRP.
  2910. Context - FileObject on which MDL is returned
  2911. Return Value:
  2912. STATUS_MORE_PROCESSING_REQUIRED - AFD takes care of the IRP
  2913. --*/
  2914. {
  2915. PFILE_OBJECT FileObject = Context;
  2916. IF_DEBUG (TRANSMIT) {
  2917. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  2918. "AfdRestartMdlReadComplete: Irp-%p,status-%lx,length-%p\n",
  2919. Irp,
  2920. Irp->IoStatus.Status,
  2921. Irp->IoStatus.Information));
  2922. }
  2923. //
  2924. // Dereference the file object
  2925. //
  2926. ObDereferenceObject (FileObject);
  2927. AfdRecordFileDeref ();
  2928. //
  2929. // Free the IRP since it's no longer needed.
  2930. //
  2931. IoFreeIrp( Irp );
  2932. //
  2933. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  2934. // will stop working on the IRP.
  2935. //
  2936. return STATUS_MORE_PROCESSING_REQUIRED;
  2937. } // AfdRestartMdlReadComplete
  2938. VOID
  2939. AfdLRMdlReadComplete (
  2940. PAFD_BUFFER_HEADER Pd
  2941. )
  2942. {
  2943. if (InterlockedPushEntrySList (
  2944. &AfdLRFileMdlList,
  2945. &Pd->SList)==NULL) {
  2946. AfdLRListAddItem (&AfdLRFileMdlListItem,
  2947. AfdLRProcessFileMdlList);
  2948. }
  2949. }
  2950. BOOLEAN
  2951. AfdLRProcessFileMdlList (
  2952. PAFD_LR_LIST_ITEM Item
  2953. )
  2954. {
  2955. PSINGLE_LIST_ENTRY localList;
  2956. BOOLEAN res = TRUE;
  2957. ASSERT (Item==&AfdLRFileMdlListItem);
  2958. DEBUG Item->SListLink.Next = UlongToPtr(0xBAADF00D);
  2959. localList = InterlockedFlushSList (&AfdLRFileMdlList);
  2960. while (localList!=NULL) {
  2961. PAFD_BUFFER_HEADER pd;
  2962. NTSTATUS status;
  2963. pd = CONTAINING_RECORD (localList, AFD_BUFFER_HEADER, SList);
  2964. localList = localList->Next;
  2965. if (pd->BufferLength==0) {
  2966. PAFD_BUFFER_TAG afdBufferTag = CONTAINING_RECORD (
  2967. pd,
  2968. AFD_BUFFER_TAG,
  2969. Header);
  2970. PAFD_ENDPOINT endpoint = afdBufferTag->Context;
  2971. status = AfdMdlReadComplete (afdBufferTag->FileObject,
  2972. afdBufferTag->Mdl,
  2973. &afdBufferTag->FileOffset);
  2974. if (NT_SUCCESS (status)) {
  2975. AfdReturnBuffer (&afdBufferTag->Header,
  2976. endpoint->OwningProcess);
  2977. DEREFERENCE_ENDPOINT (endpoint);
  2978. continue;
  2979. }
  2980. }
  2981. else {
  2982. PAFD_BUFFER afdBuffer = CONTAINING_RECORD (
  2983. pd,
  2984. AFD_BUFFER,
  2985. Header);
  2986. PAFD_CONNECTION connection = afdBuffer->Context;
  2987. status = AfdMdlReadComplete (afdBuffer->FileObject,
  2988. afdBuffer->Mdl->Next,
  2989. &afdBuffer->FileOffset);
  2990. if (NT_SUCCESS (status)) {
  2991. afdBuffer->Mdl->Next = NULL;
  2992. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  2993. AfdReturnBuffer (&afdBuffer->Header,
  2994. connection->OwningProcess);
  2995. DEREFERENCE_CONNECTION (connection);
  2996. continue;
  2997. }
  2998. }
  2999. if (InterlockedPushEntrySList (
  3000. &AfdLRFileMdlList,
  3001. &pd->SList)==NULL) {
  3002. ASSERT (Item->SListLink.Next==UlongToPtr(0xBAADF00D));
  3003. res = FALSE;
  3004. }
  3005. }
  3006. return res;
  3007. }
  3008. NTSTATUS
  3009. AfdTPacketsBufferRead (
  3010. PIRP TpIrp,
  3011. PAFD_BUFFER_HEADER Pd
  3012. )
  3013. /*++
  3014. Routine Description:
  3015. Performs buffered file read for file systems that do
  3016. not support caching
  3017. Arguments:
  3018. TpIrp - transmit packet irp
  3019. Pd - descriptor with file parameters for the read
  3020. Return Value:
  3021. STATUS_SUCCESS - read was completed in-line
  3022. STATUS_PENDING - read was queued to file system driver,
  3023. will complete lated
  3024. other - read failed
  3025. --*/
  3026. {
  3027. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  3028. PDEVICE_OBJECT deviceObject;
  3029. PIRP irp;
  3030. PAFD_BUFFER afdBuffer;
  3031. PIO_STACK_LOCATION irpSp;
  3032. ASSERT( AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED );
  3033. afdBuffer = CONTAINING_RECORD (Pd, AFD_BUFFER, Header);
  3034. //
  3035. // Find the device object and allocate IRP of appropriate size
  3036. // if current one does not fit or is not available at all.
  3037. //
  3038. deviceObject = IoGetRelatedDeviceObject (afdBuffer->FileObject);
  3039. if ((tpInfo->ReadIrp==NULL) ||
  3040. (tpInfo->ReadIrp->StackCount<deviceObject->StackSize)) {
  3041. if (tpInfo->ReadIrp!=NULL) {
  3042. IoFreeIrp (tpInfo->ReadIrp);
  3043. }
  3044. if (afdBuffer->Irp->StackCount<deviceObject->StackSize) {
  3045. tpInfo->ReadIrp = IoAllocateIrp (deviceObject->StackSize, FALSE);
  3046. if (tpInfo->ReadIrp==NULL) {
  3047. PAFD_ENDPOINT endpoint;
  3048. endpoint = IoGetCurrentIrpStackLocation (TpIrp)->FileObject->FsContext;
  3049. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  3050. Pd->Mdl->ByteCount = Pd->BufferLength;
  3051. AfdReturnBuffer (Pd, endpoint->OwningProcess);
  3052. return STATUS_INSUFFICIENT_RESOURCES;
  3053. }
  3054. }
  3055. else {
  3056. tpInfo->ReadIrp = afdBuffer->Irp;
  3057. }
  3058. }
  3059. //
  3060. // Mark IRP as busy and set it up
  3061. //
  3062. AFD_SET_TP_FLAGS (TpIrp, AFD_TP_READ_BUSY);
  3063. irp = tpInfo->ReadIrp;
  3064. //
  3065. // Setup and sumbit the IRP
  3066. //
  3067. irp->MdlAddress = afdBuffer->Mdl;
  3068. irp->AssociatedIrp.SystemBuffer = afdBuffer->Buffer;
  3069. irp->UserBuffer = afdBuffer->Buffer;
  3070. //
  3071. // Set current thread for IoSetHardErrorOrVerifyDevice.
  3072. //
  3073. irp->Tail.Overlay.Thread = PsGetCurrentThread ();
  3074. irp->Overlay.AsynchronousParameters.UserApcContext = Pd;
  3075. irpSp = IoGetNextIrpStackLocation( irp );
  3076. irpSp->MajorFunction = IRP_MJ_READ;
  3077. irpSp->MinorFunction = IRP_MN_NORMAL;
  3078. irpSp->FileObject = afdBuffer->FileObject;
  3079. irpSp->Parameters.Read.Length = Pd->DataLength;
  3080. irpSp->Parameters.Read.ByteOffset = Pd->FileOffset;
  3081. IoSetCompletionRoutine(
  3082. irp,
  3083. AfdRestartTPacketsBufferRead,
  3084. TpIrp,
  3085. TRUE,
  3086. TRUE,
  3087. TRUE
  3088. );
  3089. REFERENCE_TPACKETS (TpIrp);
  3090. IF_DEBUG (TRANSMIT) {
  3091. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3092. "AfdTPacketsBufferRead:"
  3093. " Initiating read, tp_info-%p,file-%p,buffer-%p,length-%lx,offset-%I64x\n",
  3094. tpInfo,
  3095. afdBuffer->FileObject,
  3096. (PVOID)afdBuffer,
  3097. afdBuffer->DataLength,
  3098. afdBuffer->FileOffset.QuadPart
  3099. ));
  3100. }
  3101. IoCallDriver (deviceObject, irp);
  3102. if (((AFD_CLEAR_TP_FLAGS (TpIrp, AFD_TP_READ_CALL_PENDING)
  3103. & (AFD_TP_READ_COMP_PENDING|AFD_TP_ABORT_PENDING))==0) &&
  3104. NT_SUCCESS (irp->IoStatus.Status) &&
  3105. AfdTPacketsContinueAfterRead (TpIrp)) {
  3106. //
  3107. // Read completed successfully inline and post-processing was successfull,
  3108. // tell the worker to go on.
  3109. //
  3110. UPDATE_TPACKETS2 (TpIrp, "BufRead completed inline with 0x%lX bytes",
  3111. (ULONG)irp->IoStatus.Information);
  3112. return STATUS_SUCCESS;
  3113. }
  3114. else {
  3115. //
  3116. // Read has not completed yet or post processing failed,
  3117. // worker should bail and we will continue when read completes
  3118. // or in final completion routine (AfdCompleteTPackets).
  3119. //
  3120. return STATUS_PENDING;
  3121. }
  3122. }
  3123. NTSTATUS
  3124. AfdRestartTPacketsBufferRead (
  3125. IN PDEVICE_OBJECT DeviceObject,
  3126. IN PIRP Irp,
  3127. IN PVOID Context
  3128. )
  3129. /*++
  3130. Routine Description:
  3131. Completion routine for buffered read.
  3132. Does another send if packet is ready or schedules worker
  3133. to do the same.
  3134. Arguments:
  3135. DeviceObject - AfdDeviceObject
  3136. Irp - read IRP being completed
  3137. Context - TpIrp
  3138. Return Value:
  3139. STATUS_MORE_PROCESSING_REQUIRED - tell IO subsystem to stop
  3140. processing the IRP (it is handled internally).
  3141. --*/
  3142. {
  3143. PIRP tpIrp = Context;
  3144. PAFD_TPACKETS_INFO_INTERNAL tpInfo = tpIrp->AssociatedIrp.SystemBuffer;
  3145. PAFD_ENDPOINT endpoint;
  3146. PAFD_BUFFER afdBuffer;
  3147. ULONG flags;
  3148. endpoint = IoGetCurrentIrpStackLocation (tpIrp)->FileObject->FsContext;
  3149. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  3150. ASSERT (AFD_GET_TPIC(tpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED);
  3151. ASSERT (tpInfo->ReadIrp == Irp ||
  3152. AFD_GET_TPIC(tpIrp)->StateFlags & AFD_TP_ABORT_PENDING);
  3153. afdBuffer = Irp->Overlay.AsynchronousParameters.UserApcContext;
  3154. IF_DEBUG (TRANSMIT) {
  3155. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3156. "AfdRestartTPacketsBufferRead: tp_info-%p,Irp-%p,status-%lx,length-%p\n",
  3157. tpInfo,
  3158. Irp,
  3159. Irp->IoStatus.Status,
  3160. Irp->IoStatus.Information));
  3161. }
  3162. //
  3163. // Insert MDL into the current chain
  3164. // even if fs driver failed so that common
  3165. // cleanup routine takes care of its disposal
  3166. // together with AfdBuffer.
  3167. //
  3168. *(tpInfo->TailMdl) = afdBuffer->Mdl;
  3169. tpInfo->TailMdl = &(afdBuffer->Mdl->Next);
  3170. ASSERT (*(tpInfo->TailMdl)==NULL);
  3171. (*tpInfo->TailPd) = &afdBuffer->Header;
  3172. tpInfo->TailPd = &(afdBuffer->Next);
  3173. ASSERT (*(tpInfo->TailPd)==NULL);
  3174. flags = AFD_CLEAR_TP_FLAGS (tpIrp, AFD_TP_READ_COMP_PENDING);
  3175. if (Irp==afdBuffer->Irp) {
  3176. //
  3177. // If abort is aready in progress, we need to use
  3178. // interlocked exchange to synchronize with
  3179. // AfdAbortTPackets which may be attempting to cancel
  3180. // this IRP.
  3181. //
  3182. if (flags & AFD_TP_ABORT_PENDING) {
  3183. #if DBG
  3184. PIRP irp =
  3185. #endif
  3186. InterlockedExchangePointer ((PVOID *)&tpInfo->ReadIrp, NULL);
  3187. ASSERT (irp==Irp || irp==(PVOID)-1);
  3188. }
  3189. else {
  3190. tpInfo->ReadIrp = NULL;
  3191. }
  3192. }
  3193. if (NT_SUCCESS (Irp->IoStatus.Status)) {
  3194. if (((flags & (AFD_TP_READ_CALL_PENDING|AFD_TP_ABORT_PENDING))==0) &&
  3195. AfdTPacketsContinueAfterRead (tpIrp)) {
  3196. //
  3197. // Read dispatch has already returned and post-processing
  3198. // was successfull, schedule the worker to continue processing
  3199. // We transfer the reference that we added when we queued the
  3200. // read to the worker.
  3201. //
  3202. UPDATE_TPACKETS2 (tpIrp, "BufRead completed in restart with %08x bytes", (ULONG)Irp->IoStatus.Information);
  3203. AfdStartTPacketsWorker (AfdTPacketsWorker, tpIrp);
  3204. return STATUS_MORE_PROCESSING_REQUIRED;
  3205. }
  3206. }
  3207. else {
  3208. AfdAbortTPackets (tpIrp, Irp->IoStatus.Status);
  3209. }
  3210. DEREFERENCE_TPACKETS (tpIrp);
  3211. return STATUS_MORE_PROCESSING_REQUIRED;
  3212. }
  3213. BOOLEAN
  3214. AfdTPacketsContinueAfterRead (
  3215. PIRP TpIrp
  3216. )
  3217. /*++
  3218. Routine Description:
  3219. Read post-processing common for cached and non-cached case.
  3220. Queues new send if packet is complete and send IRP is available
  3221. Arguments:
  3222. TpInfo - transmit packets IRP
  3223. Return Value:
  3224. TRUE - continue processing
  3225. FALSE - processing cannot be continued because there are no
  3226. available send IRPs
  3227. --*/
  3228. {
  3229. PAFD_BUFFER_HEADER pd;
  3230. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  3231. pd = CONTAINING_RECORD (tpInfo->TailPd, AFD_BUFFER_HEADER, Next);
  3232. if (!pd->PartialMessage) {
  3233. USHORT sendIrp;
  3234. sendIrp = AfdTPacketsFindSendIrp (TpIrp);
  3235. if (sendIrp!=tpInfo->NumSendIrps) {
  3236. AfdTPacketsSend (TpIrp, sendIrp);
  3237. }
  3238. else {
  3239. return FALSE;
  3240. }
  3241. }
  3242. else {
  3243. //
  3244. // Need to complete the packet chain before we can send again
  3245. //
  3246. ASSERT (tpInfo->PdLength<tpInfo->SendPacketLength);
  3247. pd->PartialMessage = FALSE;
  3248. UPDATE_TPACKETS2 (TpIrp, "Continue building packet after read, cur len: 0x%lX",
  3249. tpInfo->PdLength);
  3250. }
  3251. return TRUE;
  3252. }
  3253. VOID
  3254. AfdCompleteTPackets (
  3255. PVOID Context
  3256. )
  3257. /*++
  3258. Routine Description:
  3259. This routine is called when all activity on transmit IRP request is completed
  3260. and reference count drops to 0. It cleans up remaining resources and
  3261. completes the IRP or initiates endpoint reuse if so requested
  3262. Arguments:
  3263. Context - TransmitInfo associated with the request
  3264. Return Value:
  3265. None
  3266. --*/
  3267. {
  3268. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3269. PIRP tpIrp = Context;
  3270. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (tpIrp);
  3271. PAFD_TPACKETS_INFO_INTERNAL tpInfo = tpIrp->AssociatedIrp.SystemBuffer;
  3272. LONG sendIrp;
  3273. PAFD_ENDPOINT endpoint;
  3274. BOOLEAN checkQueue;
  3275. PIRP nextIrp = NULL;
  3276. ASSERT (AFD_GET_TPIC(tpIrp)->ReferenceCount==0);
  3277. endpoint = irpSp->FileObject->FsContext;
  3278. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  3279. ASSERT ((AFD_GET_TPIC(tpIrp)->StateFlags
  3280. & (AFD_TP_SEND_BUSY(0) |
  3281. AFD_TP_SEND_BUSY(1) |
  3282. AFD_TP_READ_BUSY)) == 0);
  3283. if (tpInfo!=NULL) {
  3284. KIRQL currentIrql;
  3285. currentIrql = KeGetCurrentIrql ();
  3286. IF_DEBUG (TRANSMIT) {
  3287. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3288. "AfdCompleteTPackets: tp_info-%p, irql-%x\n",
  3289. tpInfo, currentIrql));
  3290. }
  3291. UPDATE_TPACKETS2 (tpIrp, "CompletTPackets @ irql %lx", currentIrql);
  3292. //
  3293. // Cleanup what's in the TpInfo structure
  3294. //
  3295. if (tpInfo->HeadMdl!=NULL) {
  3296. tpInfo->TailMdl = &tpInfo->HeadMdl;
  3297. tpInfo->TailPd = &tpInfo->HeadPd;
  3298. if (!AfdCleanupPacketChain (tpIrp, currentIrql<=APC_LEVEL)) {
  3299. ASSERT (currentIrql>APC_LEVEL);
  3300. AfdStartTPacketsWorker (AfdCompleteTPackets, tpIrp);
  3301. return;
  3302. }
  3303. }
  3304. //
  3305. // Cleanup what remains in IRPs
  3306. //
  3307. for (sendIrp=0; sendIrp<tpInfo->NumSendIrps ; sendIrp++) {
  3308. if (tpInfo->SendIrp[sendIrp]!=NULL) {
  3309. if (tpInfo->SendIrp[sendIrp]->MdlAddress!=NULL) {
  3310. tpInfo->HeadMdl = tpInfo->SendIrp[sendIrp]->MdlAddress;
  3311. tpInfo->TailMdl = &tpInfo->HeadMdl;
  3312. tpInfo->SendIrp[sendIrp]->MdlAddress = NULL;
  3313. tpInfo->HeadPd = tpInfo->SendIrp[sendIrp]->Overlay.AsynchronousParameters.UserApcContext;
  3314. tpInfo->TailPd = &tpInfo->HeadPd;
  3315. tpInfo->SendIrp[sendIrp]->Overlay.AsynchronousParameters.UserApcContext = NULL;
  3316. if (!AfdCleanupPacketChain (tpIrp, currentIrql<=APC_LEVEL)) {
  3317. ASSERT (currentIrql>APC_LEVEL);
  3318. AfdStartTPacketsWorker (AfdCompleteTPackets, tpIrp);
  3319. return;
  3320. }
  3321. }
  3322. tpInfo->SendIrp[sendIrp]->Cancel = FALSE; // So we can reuse it.
  3323. }
  3324. }
  3325. //
  3326. // Free read IRP if we used one
  3327. //
  3328. if (tpInfo->ReadIrp!=NULL) {
  3329. IoFreeIrp (tpInfo->ReadIrp);
  3330. tpInfo->ReadIrp = NULL;
  3331. }
  3332. }
  3333. ASSERT (tpIrp->Tail.Overlay.ListEntry.Flink == NULL);
  3334. //
  3335. // If request succeeded and reuse is required, attempt to
  3336. // initiate it
  3337. //
  3338. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  3339. if ( NT_SUCCESS(tpIrp->IoStatus.Status) &&
  3340. (irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_REUSE_SOCKET) != 0 ) {
  3341. PAFD_CONNECTION connection;
  3342. IS_VC_ENDPOINT (endpoint);
  3343. //
  3344. // Check if we still have endpoint and connection intact
  3345. // under the lock. If this is not the case, we won't try
  3346. // to reuse it (it must have been closed or aborted).
  3347. //
  3348. connection = endpoint->Common.VcConnecting.Connection;
  3349. if (connection!=NULL) {
  3350. ASSERT (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND ||
  3351. connection->AbortIndicated);
  3352. //
  3353. // Remember that there is a transmit IRP pended on the endpoint,
  3354. // so that when we're freeing up the connection we also complete
  3355. // the transmit IRP.
  3356. //
  3357. connection->ClosePendedTransmit = TRUE;
  3358. //
  3359. // Since we are going to effectively close this connection,
  3360. // remember that we have started cleanup on this connection.
  3361. // This allows AfdDeleteConnectedReference to remove the
  3362. // connected reference when appropriate.
  3363. //
  3364. connection->CleanupBegun = TRUE;
  3365. //
  3366. // Delete the endpoint's reference to the connection in
  3367. // preparation for reusing this endpoint.
  3368. //
  3369. endpoint->Common.VcConnecting.Connection = NULL;
  3370. //
  3371. // This is to simplify debugging.
  3372. // If connection is not being closed by the transport
  3373. // we want to be able to find it in the debugger faster
  3374. // then thru !poolfind AfdC.
  3375. //
  3376. endpoint->WorkItem.Context = connection;
  3377. //
  3378. // We are going to free TPackets info since we are done
  3379. // with sends and no longer need this.
  3380. // This will also be our indication that we are in the
  3381. // reuse state (for the cancel routine).
  3382. //
  3383. tpIrp->AssociatedIrp.SystemBuffer = (PVOID)-1;
  3384. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  3385. if ((AFD_GET_TPIC(tpIrp)->StateFlags & AFD_TP_SEND_AND_DISCONNECT)
  3386. && !connection->DisconnectIndicated
  3387. && !connection->AbortIndicated) {
  3388. ASSERT (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND);
  3389. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  3390. AfdDisconnectEventHandler (endpoint,
  3391. connection,
  3392. 0, NULL, 0, NULL,
  3393. TDI_DISCONNECT_RELEASE
  3394. );
  3395. DEREFERENCE_CONNECTION2 (connection, "S&D disconnect", 0);
  3396. }
  3397. else
  3398. #endif
  3399. {
  3400. //
  3401. // Attempt to remove the connected reference.
  3402. //
  3403. AfdDeleteConnectedReference( connection, TRUE );
  3404. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  3405. DEREFERENCE_CONNECTION2 (connection,
  3406. "No S&D disconnect, flags: %lx",
  3407. connection->ConnectionStateFlags);
  3408. }
  3409. IF_DEBUG (TRANSMIT) {
  3410. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3411. "AfdCompleteTPackets: tp_info-%p, initiating reuse\n",
  3412. tpInfo));
  3413. }
  3414. if (tpInfo!=NULL) {
  3415. AfdReturnTpInfo (tpInfo);
  3416. }
  3417. //
  3418. // DO NOT access the IRP after this point, since it may have
  3419. // been completed inside AfdDereferenceConnection!
  3420. //
  3421. return;
  3422. }
  3423. UPDATE_ENDPOINT (endpoint);
  3424. }
  3425. if (NT_SUCCESS (tpIrp->IoStatus.Status)) {
  3426. ASSERT (AFD_GET_TPIC(tpIrp)->EndpQueueEntry.Flink==NULL ||
  3427. irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT);
  3428. if (endpoint->Irp==tpIrp) {
  3429. endpoint->Irp = NULL;
  3430. }
  3431. }
  3432. else {
  3433. if (endpoint->Irp==tpIrp) {
  3434. //
  3435. // Check if all sends has been completed and IRP is not
  3436. // a part of the queue.
  3437. //
  3438. if (AFD_GET_TPIC(tpIrp)->EndpQueueEntry.Flink!=NULL) {
  3439. //
  3440. // Irp is still a part of the queue. Check
  3441. // if anything else is there and schedule processing.
  3442. //
  3443. if (!IsListEmpty (&AFD_GET_TPIC(tpIrp)->EndpQueueEntry)) {
  3444. ASSERT (!(irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT));
  3445. nextIrp = CONTAINING_RECORD (
  3446. AFD_GET_TPIC(tpIrp)->EndpQueueEntry.Flink,
  3447. IRP,
  3448. Tail.Overlay.DriverContext);
  3449. //
  3450. // Remove the original IRP from the beginning of the queue.
  3451. //
  3452. RemoveEntryList (&AFD_GET_TPIC(tpIrp)->EndpQueueEntry);
  3453. }
  3454. AFD_GET_TPIC(tpIrp)->EndpQueueEntry.Flink = NULL;
  3455. }
  3456. endpoint->Irp = nextIrp;
  3457. }
  3458. else if (endpoint->Irp!=NULL) {
  3459. nextIrp = endpoint->Irp;
  3460. if (AfdGetTPacketsReference (nextIrp)) {
  3461. ASSERT (nextIrp->AssociatedIrp.SystemBuffer!=(PVOID)-1);
  3462. }
  3463. else {
  3464. nextIrp = NULL;
  3465. }
  3466. }
  3467. }
  3468. UPDATE_ENDPOINT2 (endpoint, "Completing irp with status: %lx", tpIrp->IoStatus.Status);
  3469. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  3470. if (NT_SUCCESS(tpIrp->IoStatus.Status) &&
  3471. (AFD_GET_TPIC(tpIrp)->StateFlags & AFD_TP_SEND_AND_DISCONNECT) &&
  3472. (endpoint->Common.VcConnecting.Connection!=NULL) ) {
  3473. PAFD_CONNECTION connection;
  3474. ASSERT (IS_VC_ENDPOINT (endpoint));
  3475. connection = endpoint->Common.VcConnecting.Connection;
  3476. REFERENCE_CONNECTION (connection);
  3477. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  3478. AfdAbortConnection (connection);
  3479. }
  3480. else
  3481. #endif // TDI_SERVICE_SEND_AND_DISCONNECT
  3482. {
  3483. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  3484. }
  3485. if (IoSetCancelRoutine( tpIrp, NULL ) == NULL) {
  3486. KIRQL cancelIrql;
  3487. //
  3488. // The cancel routine has or is about to run. Synchonize with
  3489. // the cancel routine by acquiring and releasing the cancel
  3490. // and endpoint spinlocks. The cancel routine won't touch
  3491. // the IRP as it will see that its reference count is 0 and SystemBuffer
  3492. // is not yet NULL.
  3493. //
  3494. IoAcquireCancelSpinLock (&cancelIrql);
  3495. ASSERT( tpIrp->Cancel );
  3496. IoReleaseCancelSpinLock (cancelIrql);
  3497. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  3498. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  3499. }
  3500. if (irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT) {
  3501. ASSERT (nextIrp==NULL);
  3502. AFD_END_STATE_CHANGE (endpoint);
  3503. }
  3504. checkQueue = (tpIrp->Tail.Overlay.ListEntry.Blink == NULL);
  3505. IF_DEBUG (TRANSMIT) {
  3506. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3507. "AfdCompleteTPackets: tp_info-%p, completing IRP-%p\n",
  3508. tpInfo, tpIrp));
  3509. }
  3510. tpIrp->AssociatedIrp.SystemBuffer = NULL;
  3511. if (tpInfo!=NULL) {
  3512. AfdReturnTpInfo (tpInfo);
  3513. }
  3514. IoCompleteRequest( tpIrp, AfdPriorityBoost );
  3515. //
  3516. // If we're enforcing a maximum active TransmitFile count,
  3517. // and this Irp was counted towards active maximum, then
  3518. // check the list of queued TransmitFile requests and start the
  3519. // next one.
  3520. //
  3521. if( (AfdMaxActiveTransmitFileCount > 0) &&
  3522. checkQueue ) {
  3523. AfdStartNextQueuedTransmit();
  3524. }
  3525. if (nextIrp) {
  3526. if (nextIrp->AssociatedIrp.SystemBuffer) {
  3527. //
  3528. // This is transmit IRP.
  3529. // For VC endpoints, we have to fail all the onces that
  3530. // follow as long as at least one fails - the connection
  3531. // is most likely broken anyway.
  3532. // For datagrams, we can still send (at least try).
  3533. //
  3534. if (IS_VC_ENDPOINT(endpoint)) {
  3535. AfdAbortTPackets (nextIrp, STATUS_CANCELLED);
  3536. DEREFERENCE_TPACKETS_S (nextIrp);
  3537. }
  3538. else {
  3539. if( AfdMaxActiveTransmitFileCount == 0 ||
  3540. !AfdQueueTransmit (nextIrp)) {
  3541. AfdStartTPacketsWorker (AfdTPacketsWorker, nextIrp);
  3542. }
  3543. }
  3544. }
  3545. else {
  3546. //
  3547. // DisconnectEx IRP.
  3548. // If we are asked to reuse, we'll attempt to do so
  3549. // even if something failed.
  3550. //
  3551. ASSERT (IS_VC_ENDPOINT (endpoint));
  3552. irpSp = IoGetCurrentIrpStackLocation (nextIrp);
  3553. if ((irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_REUSE_SOCKET)==0) {
  3554. AfdAbortTPackets (nextIrp, STATUS_CANCELLED);
  3555. }
  3556. DEREFERENCE_TPACKETS (nextIrp);
  3557. }
  3558. }
  3559. }
  3560. VOID
  3561. AfdAbortTPackets (
  3562. PIRP TpIrp,
  3563. NTSTATUS Status
  3564. )
  3565. /*++
  3566. Routine Description:
  3567. This routine is used to stop the transmit file request in progress
  3568. and save the status which would be reported to the app as the
  3569. cause of failure
  3570. Arguments:
  3571. TransmitInfo - trasnmit info structure associated with the request
  3572. Status - status code for the error that caused the abort
  3573. Return Value:
  3574. None
  3575. --*/
  3576. {
  3577. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  3578. LONG stateFlags, newStateFlags;
  3579. USHORT sendIrp;
  3580. do {
  3581. newStateFlags = stateFlags = AFD_GET_TPIC(TpIrp)->StateFlags;
  3582. if (newStateFlags & AFD_TP_ABORT_PENDING) {
  3583. return;
  3584. }
  3585. newStateFlags |= AFD_TP_ABORT_PENDING;
  3586. }
  3587. while (InterlockedCompareExchange (
  3588. (PLONG)&AFD_GET_TPIC(TpIrp)->StateFlags,
  3589. newStateFlags,
  3590. stateFlags)!=stateFlags);
  3591. if (NT_SUCCESS (TpIrp->IoStatus.Status)) {
  3592. TpIrp->IoStatus.Status = Status;
  3593. UPDATE_TPACKETS2 (TpIrp, "Abort with status: %lx", Status);
  3594. }
  3595. if (tpInfo!=NULL) {
  3596. //
  3597. // Cancel any outstanding IRPs. It is safe to cancel IRPs even if
  3598. // they are already completed and before they are submitted
  3599. // (although we try to avoid doing this unnecessarily).
  3600. // Note that the completion pending flag can be set even
  3601. // before the irp is allocated, so check for NULL is important.
  3602. // However, after IRP is allocated and assigned, it is not freed
  3603. // until transmit packets is completed.
  3604. //
  3605. for (sendIrp=0; sendIrp<tpInfo->NumSendIrps; sendIrp++) {
  3606. if (tpInfo->SendIrp[sendIrp]!=NULL &&
  3607. AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_SEND_COMP_PENDING(sendIrp)) {
  3608. IF_DEBUG (TRANSMIT) {
  3609. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3610. "AfdAbortTPackets: tp_info-%p, canceling send irp1-%p\n",
  3611. tpInfo,
  3612. tpInfo->SendIrp[sendIrp]));
  3613. }
  3614. UPDATE_TPACKETS2 (TpIrp, "Aborting send irp %ld", sendIrp);
  3615. IoCancelIrp (tpInfo->SendIrp[sendIrp]);
  3616. }
  3617. }
  3618. if (AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_READ_COMP_PENDING) {
  3619. do {
  3620. PIRP irp;
  3621. //
  3622. // Check if completion routine did not manage
  3623. // to reset this IRP (because it was part of
  3624. // AFD buffer structure - buffered reads case).
  3625. //
  3626. irp = tpInfo->ReadIrp;
  3627. ASSERT (irp!=(PVOID)-1);
  3628. if (irp==NULL) {
  3629. break;
  3630. }
  3631. //
  3632. // Set this field to a "special" value so that
  3633. // we know if we need to reset it back to previous
  3634. // value when we are done with the IRP or if completion
  3635. // rouine done this already.
  3636. //
  3637. else if (InterlockedCompareExchangePointer (
  3638. (PVOID *)&tpInfo->ReadIrp,
  3639. (PVOID)-1,
  3640. irp)==irp) {
  3641. IF_DEBUG (TRANSMIT) {
  3642. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3643. "AfdAbortTPackets: tp_info-%p, canceling read irp-%p\n",
  3644. tpInfo,
  3645. irp));
  3646. }
  3647. UPDATE_TPACKETS2 (TpIrp, "Aborting read IRP", 0);
  3648. IoCancelIrp (irp);
  3649. //
  3650. // Reset the field to its original value
  3651. // unless completion routine already done this for us.
  3652. //
  3653. #if DBG
  3654. irp =
  3655. #endif
  3656. InterlockedCompareExchangePointer (
  3657. (PVOID *)&tpInfo->ReadIrp,
  3658. irp,
  3659. (PVOID)-1);
  3660. ASSERT (irp==NULL || irp==(PVOID)-1);
  3661. break;
  3662. }
  3663. }
  3664. while (1);
  3665. }
  3666. }
  3667. }
  3668. VOID
  3669. AfdCancelTPackets (
  3670. IN PDEVICE_OBJECT DeviceObject,
  3671. IN PIRP Irp
  3672. )
  3673. /*++
  3674. Routine Description:
  3675. The cancel routine for transmit packets requests.
  3676. Arguments:
  3677. DeviceObject - ignored.
  3678. Irp - a pointer to the transmit packets IRP to cancel.
  3679. Return Value:
  3680. None.
  3681. --*/
  3682. {
  3683. PIO_STACK_LOCATION irpSp;
  3684. PAFD_ENDPOINT endpoint;
  3685. PAFD_TPACKETS_INFO_INTERNAL tpInfo;
  3686. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3687. AFD_LOCK_QUEUE_HANDLE transmitLockHandle;
  3688. //
  3689. // Initialize some locals and grab the endpoint spin lock.
  3690. //
  3691. irpSp = IoGetCurrentIrpStackLocation( Irp );
  3692. endpoint = irpSp->FileObject->FsContext;
  3693. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  3694. tpInfo = Irp->AssociatedIrp.SystemBuffer;
  3695. ASSERT (KeGetCurrentIrql ()==DISPATCH_LEVEL);
  3696. AfdAcquireSpinLockAtDpcLevel( &endpoint->SpinLock, &lockHandle);
  3697. //
  3698. // We can release cancel spinlock as we hold endpoint lock now.
  3699. //
  3700. IoReleaseCancelSpinLock (DISPATCH_LEVEL);
  3701. //
  3702. // If this transmit IRP is on the TransmitFile queue, remove it.
  3703. //
  3704. AfdAcquireSpinLockAtDpcLevel( &AfdQueuedTransmitFileSpinLock,
  3705. &transmitLockHandle);
  3706. if ( Irp->Tail.Overlay.ListEntry.Flink != NULL ) {
  3707. ASSERT (tpInfo!=NULL && tpInfo!=(PVOID)-1);
  3708. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  3709. //
  3710. // Reset Flink to indicate that IRP is no longer in the queue
  3711. // Note that Blink is not reset so that completion routine knows
  3712. // that this IRP was not counted towards active maximum and thus
  3713. // new IRP should not be initiated when this one is being
  3714. // completed.
  3715. //
  3716. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  3717. ASSERT (Irp->Tail.Overlay.ListEntry.Blink!=NULL);
  3718. AfdReleaseSpinLockFromDpcLevel( &AfdQueuedTransmitFileSpinLock, &transmitLockHandle );
  3719. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  3720. KeLowerIrql (Irp->CancelIrql);
  3721. //
  3722. // Although we know that there is nothing to abort, we call
  3723. // this routine to set the status code in the IRP.
  3724. //
  3725. AfdAbortTPackets (Irp, STATUS_CANCELLED);
  3726. IF_DEBUG (TRANSMIT) {
  3727. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3728. "AfdCancelTPackets: Removed from the queue, tp_info-%p, irp-%p\n",
  3729. tpInfo, Irp));
  3730. }
  3731. //
  3732. // Remove initial reference
  3733. //
  3734. DEREFERENCE_TPACKETS (Irp);
  3735. }
  3736. else {
  3737. KIRQL cancelIrql = Irp->CancelIrql;
  3738. AfdReleaseSpinLockFromDpcLevel( &AfdQueuedTransmitFileSpinLock,
  3739. &transmitLockHandle);
  3740. if (AfdGetTPacketsReference (Irp)) {
  3741. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  3742. if (cancelIrql!=DISPATCH_LEVEL) {
  3743. KeLowerIrql (cancelIrql);
  3744. }
  3745. //
  3746. // Transmit is still in progress, perform the abort
  3747. //
  3748. AfdAbortTPackets (Irp, STATUS_CANCELLED);
  3749. //
  3750. // Remove extra reference that we added above.
  3751. //
  3752. DEREFERENCE_TPACKETS (Irp);
  3753. }
  3754. else if (tpInfo==(PVOID)-1) {
  3755. //
  3756. // Endpoint is being disconnected and reused just complete the IRP
  3757. // (we reset the pointer to it so that reuse routine won't do it again).
  3758. //
  3759. BOOLEAN checkQueue = (Irp->Tail.Overlay.ListEntry.Blink == NULL);
  3760. ASSERT (endpoint->Irp==Irp);
  3761. endpoint->Irp = NULL;
  3762. //
  3763. // Reset the pointer so we do not confuse the IO subsystem
  3764. //
  3765. Irp->AssociatedIrp.SystemBuffer = NULL;
  3766. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  3767. if (Irp->CancelIrql!=DISPATCH_LEVEL) {
  3768. KeLowerIrql (Irp->CancelIrql);
  3769. }
  3770. IF_DEBUG (TRANSMIT) {
  3771. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3772. "AfdCancelTPackets: Completing, irp-%p\n",
  3773. Irp));
  3774. }
  3775. UPDATE_ENDPOINT (endpoint);
  3776. Irp->IoStatus.Status = STATUS_CANCELLED;
  3777. IoCompleteRequest (Irp, AfdPriorityBoost);
  3778. //
  3779. // If we're enforcing a maximum active TransmitFile count,
  3780. // and this Irp was counted towards active maximum, then
  3781. // check the list of queued TransmitFile requests and start the
  3782. // next one.
  3783. //
  3784. if( AfdMaxActiveTransmitFileCount > 0 && checkQueue) {
  3785. AfdStartNextQueuedTransmit();
  3786. }
  3787. }
  3788. else {
  3789. //
  3790. // Everything is done anyway, let go.
  3791. //
  3792. AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle);
  3793. if (cancelIrql!=DISPATCH_LEVEL) {
  3794. KeLowerIrql (cancelIrql);
  3795. }
  3796. }
  3797. }
  3798. } // AfdCancelTPackets
  3799. VOID
  3800. AfdCompleteClosePendedTPackets (
  3801. PAFD_ENDPOINT Endpoint
  3802. )
  3803. /*++
  3804. Routine Description:
  3805. Completes a transmit IRP that was waiting for the connection to be
  3806. completely disconnected.
  3807. Arguments:
  3808. Endpoint - the endpoint on which the transmit request is pending.
  3809. Return Value:
  3810. None.
  3811. --*/
  3812. {
  3813. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3814. PIRP tpIrp;
  3815. BOOLEAN checkQueue;
  3816. AfdAcquireSpinLock( &Endpoint->SpinLock, &lockHandle );
  3817. //
  3818. // First make sure that thre is really a transmit request pended on
  3819. // this endpoint. We do this while holding the appropriate locks
  3820. // to close the timing window that would exist otherwise, since
  3821. // the caller may not have had the locks when making the test.
  3822. //
  3823. tpIrp = Endpoint->Irp;
  3824. if ( tpIrp == NULL ) {
  3825. IF_DEBUG (TRANSMIT) {
  3826. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3827. "AfdCompleteClosePendedTPackets: Irp is gone, endpoint-%p",
  3828. Endpoint));
  3829. }
  3830. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  3831. return;
  3832. }
  3833. ASSERT (tpIrp->AssociatedIrp.SystemBuffer == (PVOID)-1);
  3834. tpIrp->AssociatedIrp.SystemBuffer = NULL;
  3835. Endpoint->Irp = NULL;
  3836. //
  3837. // Release the lock before completing the transmit IRP--it is
  3838. // illegal to call IoCompleteRequest while holding a spin lock.
  3839. //
  3840. AfdReleaseSpinLock( &Endpoint->SpinLock, &lockHandle );
  3841. //
  3842. // Reset the cancel routine in the IRP before attempting to complete
  3843. // it.
  3844. //
  3845. if ( IoSetCancelRoutine( tpIrp, NULL ) == NULL ) {
  3846. KIRQL cancelIrql;
  3847. //
  3848. // The cancel routine has or is about to run. Synchonize with
  3849. // the cancel routine by acquiring and releasing the cancel
  3850. // and endpoint spinlocks. The cancel routine won't touch
  3851. // the IRP as it will see that IRP pointer was reset in the
  3852. // transmit info structure.
  3853. //
  3854. IoAcquireCancelSpinLock (&cancelIrql);
  3855. ASSERT( tpIrp->Cancel );
  3856. IoReleaseCancelSpinLock (cancelIrql);
  3857. }
  3858. //
  3859. // Make sure to refresh the endpoint BEFORE completing the transmit
  3860. // IRP. This is because the user-mode caller may reuse the endpoint
  3861. // as soon as the IRP completes, and there would be a timing window
  3862. // between reuse of the endpoint and the refresh otherwise.
  3863. //
  3864. AfdRefreshEndpoint( Endpoint );
  3865. ASSERT (tpIrp->IoStatus.Status==STATUS_SUCCESS);
  3866. AFD_END_STATE_CHANGE (Endpoint);
  3867. checkQueue = (tpIrp->Tail.Overlay.ListEntry.Blink == NULL);
  3868. IF_DEBUG (TRANSMIT) {
  3869. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3870. "AfdCompleteClosePendedTPackets: Completing irp-%p",
  3871. tpIrp));
  3872. }
  3873. //
  3874. // Finally, we can complete the transmit request.
  3875. //
  3876. UPDATE_ENDPOINT(Endpoint);
  3877. IoCompleteRequest( tpIrp, AfdPriorityBoost );
  3878. //
  3879. // If we're enforcing a maximum active TransmitFile count,
  3880. // and this Irp was counted towards active maximum, then
  3881. // check the list of queued TransmitFile requests and start the
  3882. // next one.
  3883. //
  3884. if( (AfdMaxActiveTransmitFileCount > 0) &&
  3885. checkQueue) {
  3886. AfdStartNextQueuedTransmit();
  3887. }
  3888. } // AfdCompleteClosePendedTPackets
  3889. #ifdef TDI_SERVICE_SEND_AND_DISCONNECT
  3890. BOOLEAN
  3891. AfdTPacketsEnableSendAndDisconnect (
  3892. PIRP TpIrp
  3893. )
  3894. /*++
  3895. Routine Description:
  3896. Check if combined send and disconnect can be used and update
  3897. endpoint state appropriately
  3898. Arguments:
  3899. TpIrp - transmit packets IRP
  3900. Return Value:
  3901. TRUE - S&D can be used, endpoint state updated.
  3902. FALSE - no, use normal disconnect (which updates the state by itself).
  3903. --*/
  3904. {
  3905. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  3906. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (TpIrp);
  3907. PAFD_ENDPOINT endpoint;
  3908. BOOLEAN res = FALSE;
  3909. endpoint = irpSp->FileObject->FsContext;
  3910. if ( AfdUseTdiSendAndDisconnect &&
  3911. (irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_REUSE_SOCKET) &&
  3912. (endpoint->TdiServiceFlags & TDI_SERVICE_SEND_AND_DISCONNECT)) {
  3913. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3914. ASSERT (IS_VC_ENDPOINT (endpoint));
  3915. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  3916. if (!(endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) &&
  3917. endpoint->Common.VcConnecting.Connection!=NULL &&
  3918. endpoint->Common.VcConnecting.Connection->ConnectDataBuffers==NULL
  3919. ) {
  3920. endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_SEND;
  3921. res = TRUE;
  3922. UPDATE_TPACKETS2 (TpIrp, "Enabling S&D", 0);
  3923. }
  3924. else {
  3925. UPDATE_TPACKETS2 (TpIrp, "Disabling S&D, disconnect mode: %lx",
  3926. endpoint->DisconnectMode);
  3927. }
  3928. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  3929. }
  3930. else {
  3931. UPDATE_TPACKETS2 (TpIrp,
  3932. "Not enabling S&D, flags: %lx",
  3933. irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags);
  3934. }
  3935. return res;
  3936. }
  3937. #endif // TDI_SERVICE_SEND_AND_DISCONNECT
  3938. BOOLEAN
  3939. AfdQueueTransmit (
  3940. PIRP Irp
  3941. )
  3942. /*++
  3943. Routine Description:
  3944. Check transmit IRP can be process immediately or needs to be put
  3945. in the queue because of exceeded simmulteneous send limit
  3946. Arguments:
  3947. Irp - TransmitIrp
  3948. Return Value:
  3949. TRUE - Irp was queued, can't send
  3950. FALSE - We are below the limit, go ahed and send.
  3951. --*/
  3952. {
  3953. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3954. AfdAcquireSpinLock (&AfdQueuedTransmitFileSpinLock, &lockHandle);
  3955. if( AfdActiveTransmitFileCount >= AfdMaxActiveTransmitFileCount ) {
  3956. InsertTailList(
  3957. &AfdQueuedTransmitFileListHead,
  3958. &Irp->Tail.Overlay.ListEntry
  3959. );
  3960. UPDATE_TPACKETS2 (Irp, "Queuing, current count: %ld", AfdActiveTransmitFileCount);
  3961. AfdReleaseSpinLock (&AfdQueuedTransmitFileSpinLock, &lockHandle);
  3962. IF_DEBUG (TRANSMIT) {
  3963. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  3964. "AfdQueueTransmit: Queuing Irp-%p,endpoint-%p,tp_info-%p\n",
  3965. Irp,
  3966. IoGetCurrentIrpStackLocation (Irp)->FileObject->FsContext,
  3967. Irp->AssociatedIrp.SystemBuffer));
  3968. }
  3969. return TRUE;
  3970. } else {
  3971. AfdActiveTransmitFileCount++;
  3972. AfdReleaseSpinLock (&AfdQueuedTransmitFileSpinLock, &lockHandle);
  3973. return FALSE;
  3974. }
  3975. }
  3976. VOID
  3977. AfdStartNextQueuedTransmit(
  3978. VOID
  3979. )
  3980. /*++
  3981. Routine Description:
  3982. Starts next transmit file in the queue if the number of pending
  3983. request drops below maximum
  3984. Arguments:
  3985. None.
  3986. Return Value:
  3987. None.
  3988. --*/
  3989. {
  3990. AFD_LOCK_QUEUE_HANDLE lockHandle;
  3991. PLIST_ENTRY listEntry;
  3992. PIRP irp;
  3993. PAFD_TPACKETS_INFO_INTERNAL tpInfo;
  3994. //
  3995. // This should only be called if we're actually enforcing a maximum
  3996. // TransmitFile count.
  3997. //
  3998. ASSERT( AfdMaxActiveTransmitFileCount > 0 );
  3999. //
  4000. // The TransmitFile request queue is protected by a
  4001. // spinlock, so grab that lock before examining the queue.
  4002. //
  4003. AfdAcquireSpinLock( &AfdQueuedTransmitFileSpinLock, &lockHandle );
  4004. //
  4005. // This routine is only called after a pended TransmitFile IRP
  4006. // completes, so account for that completion here.
  4007. //
  4008. ASSERT( AfdActiveTransmitFileCount > 0 );
  4009. AfdActiveTransmitFileCount--;
  4010. if( !IsListEmpty( &AfdQueuedTransmitFileListHead ) ) {
  4011. //
  4012. // Dequeue exactly one IRP from the list, then start the
  4013. // TransmitFile.
  4014. //
  4015. listEntry = RemoveHeadList(
  4016. &AfdQueuedTransmitFileListHead
  4017. );
  4018. irp = CONTAINING_RECORD(
  4019. listEntry,
  4020. IRP,
  4021. Tail.Overlay.ListEntry
  4022. );
  4023. tpInfo = irp->AssociatedIrp.SystemBuffer;
  4024. ASSERT( tpInfo != NULL );
  4025. //
  4026. // Mark this TransmitFile request as no longer queued.
  4027. // and counted towards active maximum.
  4028. //
  4029. irp->Tail.Overlay.ListEntry.Flink = NULL;
  4030. irp->Tail.Overlay.ListEntry.Blink = NULL;
  4031. //
  4032. // Adjust the count, release the spinlock, then queue the
  4033. // TransmitFile.
  4034. //
  4035. AfdActiveTransmitFileCount++;
  4036. ASSERT( AfdActiveTransmitFileCount <= AfdMaxActiveTransmitFileCount );
  4037. UPDATE_TPACKETS2 (irp,"Restarting from queue, count: %ld", AfdActiveTransmitFileCount);
  4038. AfdReleaseSpinLock( &AfdQueuedTransmitFileSpinLock, &lockHandle );
  4039. ASSERT (irp->AssociatedIrp.SystemBuffer!=NULL);
  4040. //
  4041. // Schedule the worker for the transmit.
  4042. //
  4043. AfdStartTPacketsWorker (AfdTPacketsWorker, irp);
  4044. } else {
  4045. //
  4046. // Release the spinlock before returning.
  4047. //
  4048. AfdReleaseSpinLock( &AfdQueuedTransmitFileSpinLock, &lockHandle );
  4049. }
  4050. } // AfdStartNextQueuedTransmit
  4051. BOOLEAN
  4052. AfdEnqueueTPacketsIrp (
  4053. PAFD_ENDPOINT Endpoint,
  4054. PIRP TpIrp
  4055. )
  4056. /*++
  4057. Routine Description:
  4058. Check if transmit IRP can be process immediately or needs to be put
  4059. in the queue because there is already an active transmit IRP on the
  4060. endpoint.
  4061. Arguments:
  4062. Endpoint - endpoint to check
  4063. Irp - TransmitIrp
  4064. Return Value:
  4065. TRUE - Irp was queued, can't send
  4066. FALSE - There are no other IRPs on the endpoint, can send now.
  4067. --*/
  4068. {
  4069. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4070. PIRP oldIrp;
  4071. BOOLEAN busy = FALSE;
  4072. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  4073. //
  4074. // Use interlocked operation since another thread can claim the
  4075. // spot without spinlock. Note, that the IRP field cannot be cleared
  4076. // outside of spinlock though.
  4077. //
  4078. oldIrp = InterlockedCompareExchangePointer ((PVOID *)&Endpoint->Irp,
  4079. TpIrp,
  4080. NULL);
  4081. if (oldIrp!=NULL) {
  4082. //
  4083. // Another IRP is still pending, check if sends are still
  4084. // pending.
  4085. //
  4086. if (AFD_GET_TPIC(oldIrp)->EndpQueueEntry.Flink!=NULL) {
  4087. //
  4088. // Add this IRP behind the last one in the list.
  4089. //
  4090. InsertTailList (&AFD_GET_TPIC(oldIrp)->EndpQueueEntry,
  4091. &AFD_GET_TPIC(TpIrp)->EndpQueueEntry);
  4092. //
  4093. // This IRP will not be counted towards maximum for now.
  4094. //
  4095. TpIrp->Tail.Overlay.ListEntry.Blink = (PVOID)2;
  4096. busy = TRUE;
  4097. //
  4098. // Add extra reference so that the caller can
  4099. // be sure that this IRP will not get completed before
  4100. // it can properly set it up.
  4101. //
  4102. REFERENCE_TPACKETS (TpIrp);
  4103. }
  4104. else {
  4105. //
  4106. // Sending is finished, we can replace the IRP with ours.
  4107. //
  4108. Endpoint->Irp = TpIrp;
  4109. }
  4110. }
  4111. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4112. return busy;
  4113. }
  4114. VOID
  4115. AfdStartNextTPacketsIrp (
  4116. PAFD_ENDPOINT Endpoint,
  4117. PIRP TpIrp
  4118. )
  4119. /*++
  4120. Routine Description:
  4121. Check if there are other IRPs enqueued behind the one we about
  4122. to finish with (perform last send) and start it.
  4123. Arguments:
  4124. Endpoint - endpoint to check
  4125. Irp - TransmitIrp
  4126. Return Value:
  4127. None.
  4128. --*/
  4129. {
  4130. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4131. PIRP newIrp;
  4132. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  4133. if (!IsListEmpty (&AFD_GET_TPIC(TpIrp)->EndpQueueEntry)) {
  4134. newIrp = CONTAINING_RECORD (
  4135. AFD_GET_TPIC(TpIrp)->EndpQueueEntry.Flink,
  4136. IRP,
  4137. Tail.Overlay.DriverContext);
  4138. RemoveEntryList (&AFD_GET_TPIC(TpIrp)->EndpQueueEntry);
  4139. Endpoint->Irp = newIrp;
  4140. //
  4141. // Set the field to indicate we are counting towards active
  4142. // maximum.
  4143. //
  4144. if (newIrp->AssociatedIrp.SystemBuffer!=NULL) {
  4145. //
  4146. // Regular TransmitPackets/File, mark as counted
  4147. // towards maximum. QueueTransmit will re-initalize
  4148. // if called.
  4149. //
  4150. newIrp->Tail.Overlay.ListEntry.Blink = NULL;
  4151. }
  4152. else {
  4153. //
  4154. // DisconnectEx is never counted towards maximum
  4155. //
  4156. newIrp->Tail.Overlay.ListEntry.Blink = (PVOID)3;
  4157. }
  4158. }
  4159. else {
  4160. newIrp = NULL;
  4161. }
  4162. //
  4163. // Indicate that the sends in the IRP are processed
  4164. //
  4165. AFD_GET_TPIC(TpIrp)->EndpQueueEntry.Flink = NULL;
  4166. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  4167. if (newIrp!=NULL) {
  4168. if (newIrp->AssociatedIrp.SystemBuffer!=NULL) {
  4169. if( AfdMaxActiveTransmitFileCount == 0 ||
  4170. !AfdQueueTransmit (newIrp)) {
  4171. //
  4172. // Start I/O
  4173. //
  4174. AfdStartTPacketsWorker (AfdTPacketsWorker, newIrp);
  4175. }
  4176. }
  4177. else {
  4178. //
  4179. // We never count DisconnectEx towards active maximum.
  4180. // Just queue the disconnect.
  4181. //
  4182. AfdPerformSuperDisconnect (newIrp);
  4183. }
  4184. }
  4185. }
  4186. VOID
  4187. AfdStartTPacketsWorker (
  4188. PWORKER_THREAD_ROUTINE WorkerRoutine,
  4189. PIRP TpIrp
  4190. )
  4191. /*++
  4192. Routine Description:
  4193. Posts work item to be executed at IRQL above DPC_LEVEL so that
  4194. file system can be accessed. It uses one of three methods
  4195. of doing this: special kernel APC, normal kernel APC, or
  4196. system thread (work queue item).
  4197. Arguments:
  4198. WorkerRoutine - routine to execute
  4199. TransmitInfo - associated transmit info (also parameter to
  4200. the worker routine).
  4201. Return Value:
  4202. None.
  4203. --*/
  4204. {
  4205. PAFD_TPACKETS_INFO_INTERNAL tpInfo = TpIrp->AssociatedIrp.SystemBuffer;
  4206. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (TpIrp);
  4207. ASSERT ((AFD_GET_TPIC(TpIrp)->StateFlags & AFD_TP_WORKER_SCHEDULED)
  4208. || (AFD_GET_TPIC(TpIrp)->ReferenceCount==0));
  4209. switch (irpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_WORKER_KIND_MASK) {
  4210. case AFD_TF_USE_KERNEL_APC:
  4211. //
  4212. // Initialize normal APC but with normal routine set
  4213. // to special value so we know to run the worker
  4214. // inside the special routine of normal APC and queue it
  4215. //
  4216. KeInitializeApc (&tpInfo->Apc,
  4217. PsGetThreadTcb (TpIrp->Tail.Overlay.Thread),
  4218. TpIrp->ApcEnvironment,
  4219. AfdTPacketsApcKernelRoutine,
  4220. AfdTPacketsApcRundownRoutine,
  4221. (PKNORMAL_ROUTINE)-1,
  4222. KernelMode,
  4223. NULL
  4224. );
  4225. if (KeInsertQueueApc (&tpInfo->Apc,
  4226. WorkerRoutine,
  4227. TpIrp,
  4228. AfdPriorityBoost))
  4229. return;
  4230. //
  4231. // If APC cannot be inserted into the queue, drop
  4232. // to use the system worker thread
  4233. //
  4234. break;
  4235. case AFD_TF_USE_SYSTEM_THREAD:
  4236. //
  4237. // This is the default case which is also used if everything else fails,
  4238. // so just break out.
  4239. //
  4240. break;
  4241. default:
  4242. ASSERT (!"Unknown worker type!");
  4243. __assume (0);
  4244. }
  4245. ExInitializeWorkItem (&tpInfo->WorkItem,
  4246. WorkerRoutine,
  4247. TpIrp
  4248. );
  4249. ExQueueWorkItem (&tpInfo->WorkItem, DelayedWorkQueue);
  4250. }
  4251. VOID
  4252. AfdTPacketsApcKernelRoutine (
  4253. IN struct _KAPC *Apc,
  4254. IN OUT PKNORMAL_ROUTINE *NormalRoutine,
  4255. IN OUT PVOID *NormalContext,
  4256. IN OUT PVOID *SystemArgument1,
  4257. IN OUT PVOID *SystemArgument2
  4258. )
  4259. /*++
  4260. Routine Description:
  4261. Special kernel apc routine. Executed in the context of
  4262. the target thread at APC_LEVEL
  4263. Arguments:
  4264. NormalRoutine - pointer containing address of normal routine (it will
  4265. be NULL for special kernel APC and not NULL for normal
  4266. kernel APC)
  4267. SystemArgument1 - pointer to the address of worker routine to execute
  4268. SystemArgument2 - pointer to the argument to pass to worker routine
  4269. Return Value:
  4270. None.
  4271. --*/
  4272. {
  4273. #if DBG
  4274. try {
  4275. #endif
  4276. ASSERT (CONTAINING_RECORD (Apc,AFD_TPACKETS_INFO_INTERNAL,Apc)
  4277. ==((PIRP)*SystemArgument2)->AssociatedIrp.SystemBuffer);
  4278. //
  4279. // Normal APC, but we are requested to run in its special
  4280. // routine which avoids raising and lowering IRQL
  4281. //
  4282. ASSERT (*NormalRoutine==(PKNORMAL_ROUTINE)-1);
  4283. *NormalRoutine = NULL;
  4284. ((PWORKER_THREAD_ROUTINE)*SystemArgument1) (*SystemArgument2);
  4285. #if DBG
  4286. }
  4287. except (AfdApcExceptionFilter (GetExceptionInformation (),
  4288. __FILE__,
  4289. __LINE__)) {
  4290. DbgBreakPoint ();
  4291. }
  4292. #endif
  4293. }
  4294. VOID
  4295. AfdTPacketsApcRundownRoutine (
  4296. IN struct _KAPC *Apc
  4297. )
  4298. /*++
  4299. Routine Description:
  4300. APC rundown routine. Executed if APC cannot be delivered for
  4301. some reason (thread exiting).
  4302. We just fall back to system threads to execute the worker
  4303. Arguments:
  4304. Apc - APC structure
  4305. Return Value:
  4306. None.
  4307. --*/
  4308. {
  4309. PIRP tpIrp;
  4310. PAFD_TPACKETS_INFO_INTERNAL tpInfo;
  4311. PWORKER_THREAD_ROUTINE workerRoutine;
  4312. #if DBG
  4313. try {
  4314. #endif
  4315. workerRoutine = Apc->SystemArgument1;
  4316. tpIrp = Apc->SystemArgument2;
  4317. tpInfo = tpIrp->AssociatedIrp.SystemBuffer;
  4318. ASSERT (tpInfo==CONTAINING_RECORD (Apc,AFD_TPACKETS_INFO_INTERNAL,Apc));
  4319. ExInitializeWorkItem (&tpInfo->WorkItem,
  4320. workerRoutine,
  4321. tpIrp
  4322. );
  4323. ExQueueWorkItem (&tpInfo->WorkItem, DelayedWorkQueue);
  4324. #if DBG
  4325. }
  4326. except (AfdApcExceptionFilter (GetExceptionInformation (),
  4327. __FILE__,
  4328. __LINE__)) {
  4329. DbgBreakPoint ();
  4330. }
  4331. #endif
  4332. }
  4333. BOOLEAN
  4334. AfdGetTPacketsReference (
  4335. PIRP Irp
  4336. )
  4337. {
  4338. LONG count;
  4339. //
  4340. // Only if transmit info is not completed yet, cancel all the IRPs
  4341. // We release the spinlock while cancelling the IRP, so we need
  4342. // to make sure that one of the cancelled IRPs won't initiate
  4343. // completion while we trying to cancel the other IRPs
  4344. //
  4345. do {
  4346. count = AFD_GET_TPIC(Irp)->ReferenceCount;
  4347. if (count==0) {
  4348. break;
  4349. }
  4350. }
  4351. while (InterlockedCompareExchange ((PLONG)
  4352. &AFD_GET_TPIC(Irp)->ReferenceCount,
  4353. (count+1),
  4354. count)!=count);
  4355. if (count!=0) {
  4356. return TRUE;
  4357. }
  4358. else {
  4359. return FALSE;
  4360. }
  4361. }
  4362. //
  4363. // Debug reference/dereference code, validates reference count
  4364. // and saves tracing information.
  4365. //
  4366. #if REFERENCE_DEBUG
  4367. VOID
  4368. AfdReferenceTPackets (
  4369. IN PIRP Irp,
  4370. IN LONG LocationId,
  4371. IN ULONG Param
  4372. )
  4373. {
  4374. LONG count;
  4375. do {
  4376. count = AFD_GET_TPIC(Irp)->ReferenceCount;
  4377. ASSERT (count>0);
  4378. }
  4379. while (InterlockedCompareExchange ((PLONG)
  4380. &AFD_GET_TPIC(Irp)->ReferenceCount,
  4381. (count+1),
  4382. count)!=count);
  4383. if (Irp->AssociatedIrp.SystemBuffer) {
  4384. AFD_UPDATE_REFERENCE_DEBUG (
  4385. (PAFD_TPACKETS_INFO_INTERNAL)Irp->AssociatedIrp.SystemBuffer,
  4386. count+1,
  4387. LocationId,
  4388. Param);
  4389. }
  4390. }
  4391. LONG
  4392. AfdDereferenceTPackets (
  4393. IN PIRP Irp,
  4394. IN LONG LocationId,
  4395. IN ULONG Param
  4396. )
  4397. {
  4398. LONG count;
  4399. if (Irp->AssociatedIrp.SystemBuffer) {
  4400. AFD_UPDATE_REFERENCE_DEBUG (
  4401. (PAFD_TPACKETS_INFO_INTERNAL)Irp->AssociatedIrp.SystemBuffer,
  4402. AFD_GET_TPIC(Irp)->ReferenceCount-1,
  4403. LocationId,
  4404. Param);
  4405. }
  4406. count = InterlockedDecrement ((PLONG)
  4407. &AFD_GET_TPIC(Irp)->ReferenceCount);
  4408. ASSERT (count>=0);
  4409. return count;
  4410. }
  4411. VOID
  4412. AfdUpdateTPacketsTrack (
  4413. IN PIRP Irp,
  4414. IN LONG LocationId,
  4415. IN ULONG Param
  4416. )
  4417. {
  4418. if (Irp->AssociatedIrp.SystemBuffer) {
  4419. AFD_UPDATE_REFERENCE_DEBUG (
  4420. (PAFD_TPACKETS_INFO_INTERNAL)Irp->AssociatedIrp.SystemBuffer,
  4421. AFD_GET_TPIC(Irp)->ReferenceCount,
  4422. LocationId,
  4423. Param);
  4424. }
  4425. }
  4426. #endif // REFERENCE_DEBUG
  4427. PAFD_TPACKETS_INFO_INTERNAL
  4428. AfdGetTpInfo (
  4429. ULONG ElementCount
  4430. )
  4431. {
  4432. PAFD_TPACKETS_INFO_INTERNAL tpInfo;
  4433. ASSERT (ElementCount<=(MAXULONG/sizeof (AFD_TRANSMIT_PACKETS_ELEMENT)));
  4434. tpInfo = ExAllocateFromNPagedLookasideList(&AfdLookasideLists->TpInfoList);
  4435. if (tpInfo!=NULL) {
  4436. ASSERT (tpInfo->ReadIrp==NULL);
  4437. ASSERT (tpInfo->NumSendIrps==AFD_TP_MIN_SEND_IRPS);
  4438. tpInfo->HeadMdl = NULL;
  4439. tpInfo->TailMdl = &tpInfo->HeadMdl;
  4440. tpInfo->HeadPd = NULL;
  4441. tpInfo->TailPd = &tpInfo->HeadPd;
  4442. tpInfo->PdLength = 0;
  4443. tpInfo->PdNeedsPps = FALSE;
  4444. tpInfo->NextElement = 0;
  4445. tpInfo->RemainingPkts = MAXULONG;
  4446. #if REFERENCE_DEBUG
  4447. tpInfo->CurrentReferenceSlot = -1;
  4448. RtlZeroMemory (&tpInfo->ReferenceDebug,
  4449. sizeof (tpInfo->ReferenceDebug));
  4450. #endif
  4451. #if AFD_PERF_DBG
  4452. tpInfo->WorkersExecuted = 0;
  4453. #endif
  4454. if (ElementCount<=3) {
  4455. return tpInfo;
  4456. }
  4457. try {
  4458. tpInfo->ElementArray =
  4459. AFD_ALLOCATE_POOL_WITH_QUOTA (
  4460. NonPagedPool,
  4461. ElementCount*sizeof (AFD_TRANSMIT_PACKETS_ELEMENT),
  4462. AFD_TRANSMIT_INFO_POOL_TAG);
  4463. tpInfo->ArrayAllocated = TRUE;
  4464. return tpInfo;
  4465. }
  4466. except (EXCEPTION_EXECUTE_HANDLER) {
  4467. }
  4468. AfdReturnTpInfo (tpInfo);
  4469. }
  4470. return NULL;
  4471. }
  4472. VOID
  4473. AfdReturnTpInfo (
  4474. PAFD_TPACKETS_INFO_INTERNAL TpInfo
  4475. )
  4476. {
  4477. ULONG i;
  4478. //
  4479. // Validate that built-in send IRPs are properly deinitialized.
  4480. //
  4481. #if DBG
  4482. for (i=0; i<AFD_TP_MIN_SEND_IRPS; i++) {
  4483. ASSERT (TpInfo->SendIrp[i]->MdlAddress == NULL);
  4484. ASSERT (TpInfo->SendIrp[i]->Overlay.AsynchronousParameters.UserApcContext == NULL);
  4485. ASSERT (TpInfo->SendIrp[i]->Cancel==FALSE);
  4486. }
  4487. #endif
  4488. //
  4489. // Dispose of extra allocated IRPs.
  4490. //
  4491. while (TpInfo->NumSendIrps>AFD_TP_MIN_SEND_IRPS) {
  4492. TpInfo->NumSendIrps -= 1;
  4493. if (TpInfo->SendIrp[TpInfo->NumSendIrps]!=NULL) {
  4494. IoFreeIrp (TpInfo->SendIrp[TpInfo->NumSendIrps]);
  4495. TpInfo->SendIrp[TpInfo->NumSendIrps] = NULL;
  4496. }
  4497. }
  4498. if (TpInfo->ReadIrp!=NULL) {
  4499. IoFreeIrp (TpInfo->ReadIrp);
  4500. TpInfo->ReadIrp = NULL;
  4501. }
  4502. //
  4503. // Cleanup all file objects and MDLs that we may have already referenced
  4504. //
  4505. for (i=0; i<TpInfo->ElementCount; i++) {
  4506. PAFD_TRANSMIT_PACKETS_ELEMENT pel;
  4507. pel = &TpInfo->ElementArray[i];
  4508. if (pel->Flags & TP_FILE) {
  4509. if (pel->FileObject!=NULL) {
  4510. ObDereferenceObject( pel->FileObject );
  4511. AfdRecordFileDeref();
  4512. }
  4513. }
  4514. else if (pel->Flags & TP_MDL) {
  4515. ASSERT (pel->Flags & TP_MEMORY);
  4516. if (pel->Mdl!=NULL) {
  4517. if (pel->Mdl->MdlFlags & MDL_PAGES_LOCKED) {
  4518. MmUnlockPages (pel->Mdl);
  4519. }
  4520. IoFreeMdl (pel->Mdl);
  4521. }
  4522. }
  4523. }
  4524. //
  4525. // Free non-default sized array of packets if necessary.
  4526. //
  4527. if (TpInfo->ArrayAllocated) {
  4528. AFD_FREE_POOL (TpInfo->ElementArray, AFD_TRANSMIT_INFO_POOL_TAG);
  4529. TpInfo->ElementArray = ALIGN_UP_TO_TYPE_POINTER (
  4530. (PUCHAR)TpInfo+sizeof (AFD_TPACKETS_INFO_INTERNAL),
  4531. AFD_TRANSMIT_PACKETS_ELEMENT);
  4532. TpInfo->ArrayAllocated = FALSE;
  4533. }
  4534. else {
  4535. ASSERT (TpInfo->ElementCount<=AfdDefaultTpInfoElementCount);
  4536. ASSERT (TpInfo->ElementArray == ALIGN_UP_TO_TYPE_POINTER (
  4537. (PUCHAR)TpInfo+sizeof (AFD_TPACKETS_INFO_INTERNAL),
  4538. AFD_TRANSMIT_PACKETS_ELEMENT));
  4539. }
  4540. #if AFD_PERF_DBG
  4541. InterlockedExchangeAdd (&AfdTPWorkersExecuted, TpInfo->WorkersExecuted);
  4542. InterlockedIncrement (&AfdTPRequests);
  4543. #endif
  4544. ExFreeToNPagedLookasideList( &AfdLookasideLists->TpInfoList, TpInfo );
  4545. }
  4546. ULONG
  4547. AfdComputeTpInfoSize (
  4548. ULONG ElementCount,
  4549. LONG IrpCount,
  4550. CCHAR IrpStackCount
  4551. )
  4552. {
  4553. USHORT irpSize = (USHORT)ALIGN_UP_TO_TYPE(IoSizeOfIrp (IrpStackCount), IRP);
  4554. return
  4555. ALIGN_UP_TO_TYPE(
  4556. ALIGN_UP_TO_TYPE (
  4557. sizeof (AFD_TPACKETS_INFO_INTERNAL),
  4558. AFD_TRANSMIT_PACKETS_ELEMENT ) +
  4559. ElementCount*sizeof (AFD_TRANSMIT_PACKETS_ELEMENT),
  4560. IRP ) +
  4561. irpSize*IrpCount;
  4562. }
  4563. PVOID
  4564. AfdAllocateTpInfo (
  4565. IN POOL_TYPE PoolType,
  4566. IN SIZE_T NumberOfBytes,
  4567. IN ULONG Tag
  4568. )
  4569. /*++
  4570. Routine Description:
  4571. Used by the lookaside list allocation function to allocate a new
  4572. AFD TpInfo structure. The returned structure will be fully
  4573. initialized.
  4574. Arguments:
  4575. PoolType - passed to ExAllocatePoolWithTag.
  4576. NumberOfBytes - the number of bytes required for the tp info structure
  4577. Tag - passed to ExAllocatePoolWithTag.
  4578. Return Value:
  4579. PVOID - a fully initialized TpInfo, or NULL if the allocation
  4580. attempt fails.
  4581. --*/
  4582. {
  4583. PAFD_TPACKETS_INFO_INTERNAL tpInfo;
  4584. tpInfo = AFD_ALLOCATE_POOL (
  4585. NonPagedPool,
  4586. NumberOfBytes,
  4587. AFD_TRANSMIT_INFO_POOL_TAG);
  4588. if (tpInfo!=NULL) {
  4589. USHORT irpSize = IoSizeOfIrp (AfdIrpStackSize-1);
  4590. LONG i;
  4591. RtlZeroMemory (tpInfo, sizeof (*tpInfo));
  4592. tpInfo->ElementArray = ALIGN_UP_TO_TYPE_POINTER (
  4593. (PUCHAR)tpInfo+sizeof (AFD_TPACKETS_INFO_INTERNAL),
  4594. AFD_TRANSMIT_PACKETS_ELEMENT);
  4595. tpInfo->NumSendIrps = AFD_TP_MIN_SEND_IRPS;
  4596. tpInfo->SendIrp[0] = ALIGN_UP_TO_TYPE_POINTER (
  4597. &tpInfo->ElementArray[AfdDefaultTpInfoElementCount],
  4598. IRP);
  4599. IoInitializeIrp (tpInfo->SendIrp[0], irpSize, AfdIrpStackSize-1);
  4600. tpInfo->SendIrp[0]->Overlay.AsynchronousParameters.UserApcRoutine = (PVOID)0;
  4601. for (i=1; i<AFD_TP_MIN_SEND_IRPS; i++) {
  4602. tpInfo->SendIrp[i] = ALIGN_UP_TO_TYPE_POINTER (
  4603. (PUCHAR)tpInfo->SendIrp[i-1]+irpSize,
  4604. IRP);
  4605. IoInitializeIrp (tpInfo->SendIrp[i], irpSize, AfdIrpStackSize-1);
  4606. tpInfo->SendIrp[i]->Overlay.AsynchronousParameters.UserApcRoutine = (PVOID)(UINT_PTR)i;
  4607. }
  4608. }
  4609. return tpInfo;
  4610. }
  4611. VOID
  4612. NTAPI
  4613. AfdFreeTpInfo (
  4614. PVOID TpInfo
  4615. )
  4616. {
  4617. ASSERT (((PAFD_TPACKETS_INFO_INTERNAL)TpInfo)->ElementArray == ALIGN_UP_TO_TYPE_POINTER (
  4618. (PUCHAR)TpInfo+sizeof (AFD_TPACKETS_INFO_INTERNAL),
  4619. AFD_TRANSMIT_PACKETS_ELEMENT));
  4620. AFD_FREE_POOL (TpInfo, AFD_TRANSMIT_INFO_POOL_TAG);
  4621. }
  4622. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4623. *
  4624. * T R A N S M I T F I L E I M P L E M E N T A T I O N
  4625. *
  4626. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  4627. NTSTATUS
  4628. AfdRestartFastTransmitSend (
  4629. IN PDEVICE_OBJECT DeviceObject,
  4630. IN PIRP Irp,
  4631. IN PVOID Context
  4632. );
  4633. VOID
  4634. AfdDoMdlReadComplete (
  4635. PVOID Context
  4636. );
  4637. VOID
  4638. AfdFastTransmitApcRundownRoutine (
  4639. IN struct _KAPC *Apc
  4640. );
  4641. VOID
  4642. AfdFastTransmitApcKernelRoutine (
  4643. IN struct _KAPC *Apc,
  4644. IN OUT PKNORMAL_ROUTINE *NormalRoutine,
  4645. IN OUT PVOID *NormalContext,
  4646. IN OUT PVOID *SystemArgument1,
  4647. IN OUT PVOID *SystemArgument2
  4648. );
  4649. #ifdef ALLOC_PRAGMA
  4650. #pragma alloc_text( PAGEAFD, AfdFastTransmitFile )
  4651. #pragma alloc_text( PAGEAFD, AfdRestartFastTransmitSend )
  4652. #pragma alloc_text( PAGE, AfdFastTransmitApcKernelRoutine )
  4653. #pragma alloc_text( PAGE, AfdFastTransmitApcRundownRoutine )
  4654. #pragma alloc_text( PAGE, AfdDoMdlReadComplete )
  4655. #pragma alloc_text( PAGE, AfdTransmitFile )
  4656. #endif
  4657. BOOLEAN
  4658. AfdFastTransmitFile (
  4659. IN PAFD_ENDPOINT endpoint,
  4660. IN PAFD_TRANSMIT_FILE_INFO transmitInfo,
  4661. OUT PIO_STATUS_BLOCK IoStatus
  4662. )
  4663. /*++
  4664. Routine Description:
  4665. Attempts to perform a fast TransmitFile call. This will succeed
  4666. only if the caller requests write behind, the file data to be sent
  4667. is small, and the data is in the file system cache.
  4668. Arguments:
  4669. endpoint - the endpoint of interest.
  4670. transmitInfo - AFD_TRANSMIT_FILE_INFO structure.
  4671. IoStatus - points to the IO status block that will be set on successful
  4672. return from this function.
  4673. Return Value:
  4674. TRUE if the fast path was successful; FALSE if we need to do through
  4675. the normal path.
  4676. --*/
  4677. {
  4678. PAFD_CONNECTION connection;
  4679. PAFD_BUFFER afdBuffer;
  4680. ULARGE_INTEGER sendLength;
  4681. PFILE_OBJECT fileObject;
  4682. BOOLEAN success;
  4683. BOOLEAN sendCountersUpdated;
  4684. AFD_LOCK_QUEUE_HANDLE lockHandle;
  4685. ULONG fileWriteLength, bufferLength;
  4686. NTSTATUS status;
  4687. LARGE_INTEGER fileOffset;
  4688. PMDL fileMdl;
  4689. PIRP irp;
  4690. //
  4691. // If the endpoint is shut down in any way, bail out of fast IO.
  4692. //
  4693. if ( endpoint->DisconnectMode != 0 ) {
  4694. return FALSE;
  4695. }
  4696. if ( endpoint->Type != AfdBlockTypeVcConnecting ||
  4697. endpoint->State != AfdEndpointStateConnected ) {
  4698. return FALSE;
  4699. }
  4700. //
  4701. // If the TDI provider for this endpoint supports bufferring,
  4702. // don't use fast IO.
  4703. //
  4704. if ( IS_TDI_BUFFERRING(endpoint) ) {
  4705. return FALSE;
  4706. }
  4707. //
  4708. // Make sure that the flags are specified such that a fast-path
  4709. // TransmitFile is reasonable. The caller must have specified
  4710. // the write-behind flag, but not the disconnect or reuse
  4711. // socket flags.
  4712. //
  4713. if ( ((transmitInfo->Flags &
  4714. (~(AFD_TF_WRITE_BEHIND |
  4715. AFD_TF_DISCONNECT |
  4716. AFD_TF_REUSE_SOCKET |
  4717. AFD_TF_WORKER_KIND_MASK))) != 0 ) ||
  4718. ((transmitInfo->Flags & AFD_TF_WORKER_KIND_MASK)
  4719. == AFD_TF_WORKER_KIND_MASK) ||
  4720. ((transmitInfo->Flags &(~AFD_TF_WORKER_KIND_MASK))
  4721. != AFD_TF_WRITE_BEHIND) ) {
  4722. return FALSE;
  4723. }
  4724. IF_DEBUG(FAST_IO) {
  4725. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  4726. "AfdFastTransmitFile: attempting fast IO on endp %p, "
  4727. "conn %p\n", endpoint, endpoint->Common.VcConnecting.Connection));
  4728. }
  4729. //
  4730. // Initialize locals so that cleanup is easier.
  4731. //
  4732. fileObject = NULL;
  4733. afdBuffer = NULL;
  4734. sendCountersUpdated = FALSE;
  4735. fileMdl = NULL;
  4736. //
  4737. // Calculate the length the entire send.
  4738. //
  4739. if (transmitInfo->FileHandle!=NULL) {
  4740. fileWriteLength = transmitInfo->WriteLength.LowPart;
  4741. }
  4742. else {
  4743. fileWriteLength = 0;
  4744. }
  4745. sendLength.QuadPart = (ULONGLONG)transmitInfo->HeadLength +
  4746. (ULONGLONG)fileWriteLength +
  4747. (ULONGLONG)transmitInfo->TailLength;
  4748. //
  4749. // Require the following for the fast path:
  4750. //
  4751. // - There be no limitation on the count of simultaneous
  4752. // TransmitFile calls. The fast path would work around
  4753. // this limit, if it exists.
  4754. // - The caller must specify the write length (if it specified file at all).
  4755. // - The write length must be less than the configured maximum.
  4756. // - If the entire send is larger than an AFD buffer page,
  4757. // we're going to use FsRtlMdlRead, so for purposes of
  4758. // simplicity there must be:
  4759. // - a head buffer, and
  4760. // - no tail buffer
  4761. // - The configured maximum will always be less than 4GB.
  4762. // - The head buffer, if any, fits on a single page.
  4763. //
  4764. if (AfdMaxActiveTransmitFileCount != 0
  4765. ||
  4766. (transmitInfo->FileHandle!=NULL &&
  4767. (fileWriteLength == 0 ||
  4768. transmitInfo->Offset.QuadPart <0 ))
  4769. ||
  4770. sendLength.QuadPart > AfdMaxFastTransmit
  4771. ||
  4772. ( sendLength.LowPart > AfdMaxFastCopyTransmit &&
  4773. (transmitInfo->HeadLength == 0 ||
  4774. transmitInfo->TailLength != 0 ) )
  4775. ||
  4776. transmitInfo->WriteLength.HighPart != 0
  4777. ||
  4778. transmitInfo->HeadLength > AfdBufferLengthForOnePage ) {
  4779. return FALSE;
  4780. }
  4781. AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle);
  4782. connection = endpoint->Common.VcConnecting.Connection;
  4783. if (connection==NULL) {
  4784. //
  4785. // connection might have been cleaned up by transmit file.
  4786. //
  4787. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  4788. return FALSE;
  4789. }
  4790. ASSERT( connection->Type == AfdBlockTypeConnection );
  4791. //
  4792. // Determine whether there is already too much send data
  4793. // pending on the connection. If there is too much send
  4794. // data, don't do the fast path.
  4795. //
  4796. if ( AfdShouldSendBlock( endpoint, connection, sendLength.LowPart ) ) {
  4797. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  4798. goto complete;
  4799. }
  4800. //
  4801. // Add a reference to the connection object since the send
  4802. // request will complete asynchronously.
  4803. //
  4804. REFERENCE_CONNECTION( connection );
  4805. AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
  4806. //
  4807. // AfdShouldSendBlock() updates the send counters in the AFD
  4808. // connection object. Remember this fact so that we can clean
  4809. // them up if the fast path fails after this point.
  4810. //
  4811. sendCountersUpdated = TRUE;
  4812. //
  4813. // Grab an AFD buffer large enough to hold the entire send.
  4814. //
  4815. if (sendLength.LowPart>AfdMaxFastCopyTransmit) {
  4816. bufferLength = transmitInfo->HeadLength;
  4817. }
  4818. else {
  4819. bufferLength = sendLength.LowPart;
  4820. }
  4821. if (bufferLength<max (sizeof(KAPC),sizeof (WORK_QUEUE_ITEM))) {
  4822. bufferLength = max (sizeof(KAPC),sizeof (WORK_QUEUE_ITEM));
  4823. }
  4824. afdBuffer = AfdGetBuffer( bufferLength, 0,
  4825. connection->OwningProcess );
  4826. if ( afdBuffer == NULL ) {
  4827. goto complete;
  4828. }
  4829. //
  4830. // Initialize buffer fields for proper cleanup.
  4831. //
  4832. irp = afdBuffer->Irp;
  4833. afdBuffer->Irp->Tail.Overlay.Thread = NULL;
  4834. afdBuffer->FileObject = NULL;
  4835. //
  4836. // We use exception handler because buffers are user
  4837. // mode pointers
  4838. //
  4839. try {
  4840. //
  4841. // Copy in the head and tail buffers, if necessary. Note that if we
  4842. // are goint to use MDL read, then there cannot be a tail buffer because of
  4843. // the check at the beginning of this function.
  4844. //
  4845. if ( transmitInfo->HeadLength > 0 ) {
  4846. RtlCopyMemory(
  4847. afdBuffer->Buffer,
  4848. transmitInfo->Head,
  4849. transmitInfo->HeadLength
  4850. );
  4851. }
  4852. if ( transmitInfo->TailLength > 0 ) {
  4853. RtlCopyMemory(
  4854. (PCHAR)afdBuffer->Buffer + transmitInfo->HeadLength +
  4855. fileWriteLength,
  4856. transmitInfo->Tail,
  4857. transmitInfo->TailLength
  4858. );
  4859. }
  4860. } except( AFD_EXCEPTION_FILTER(NULL) ) {
  4861. goto complete;
  4862. }
  4863. if (transmitInfo->FileHandle!=NULL) {
  4864. //
  4865. // Get a referenced pointer to the file object for the file that
  4866. // we're going to transmit. This call will fail if the file
  4867. // handle specified by the caller is invalid.
  4868. //
  4869. status = ObReferenceObjectByHandle(
  4870. transmitInfo->FileHandle,
  4871. FILE_READ_DATA,
  4872. *IoFileObjectType,
  4873. ExGetPreviousMode (),
  4874. (PVOID *)&fileObject,
  4875. NULL
  4876. );
  4877. if ( !NT_SUCCESS(status) ) {
  4878. goto complete;
  4879. }
  4880. AfdRecordFileRef();
  4881. //
  4882. // If the file system doesn't support the fast cache manager
  4883. // interface, bail and go through the IRP path.
  4884. //
  4885. if( !AFD_USE_CACHE(fileObject)) {
  4886. goto complete;
  4887. }
  4888. //
  4889. // Grab the file offset into a local so that we know that the
  4890. // offset pointer we pass to FsRtlCopyRead is valid.
  4891. //
  4892. fileOffset = transmitInfo->Offset;
  4893. if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) &&
  4894. (fileOffset.QuadPart == 0) ) {
  4895. //
  4896. // Use current offset if file is opened syncronously
  4897. // and offset is not specified.
  4898. //
  4899. fileOffset = fileObject->CurrentByteOffset;
  4900. }
  4901. //
  4902. // Get the file data. If the amount of file data is small, copy
  4903. // it directly into the AFD buffer. If it is large, get an MDL
  4904. // chain for the data and chain it on to the AFD buffer chain.
  4905. //
  4906. if ( sendLength.LowPart <= AfdMaxFastCopyTransmit ) {
  4907. success = FsRtlCopyRead(
  4908. fileObject,
  4909. &fileOffset,
  4910. fileWriteLength,
  4911. FALSE,
  4912. 0,
  4913. (PCHAR)afdBuffer->Buffer + transmitInfo->HeadLength,
  4914. IoStatus,
  4915. IoGetRelatedDeviceObject( fileObject )
  4916. );
  4917. //
  4918. // We're done with the file object, so deference it now.
  4919. //
  4920. ObDereferenceObject( fileObject );
  4921. AfdRecordFileDeref();
  4922. fileObject = NULL;
  4923. if ( !success ) {
  4924. #if AFD_PERF_DBG
  4925. InterlockedIncrement (&AfdFastTfReadFailed);
  4926. #endif
  4927. goto complete;
  4928. }
  4929. } else {
  4930. success = FsRtlMdlRead(
  4931. fileObject,
  4932. &fileOffset,
  4933. fileWriteLength,
  4934. 0,
  4935. &fileMdl,
  4936. IoStatus
  4937. );
  4938. if (success) {
  4939. //
  4940. // Save the file object in the AFD buffer. The send restart
  4941. // routine will handle dereferencing the file object and
  4942. // returning the file MDLs to the system.
  4943. //
  4944. afdBuffer->FileObject = fileObject;
  4945. afdBuffer->FileOffset = fileOffset;
  4946. //
  4947. // If caller asked us to use kernel APC to execute the request,
  4948. // allocate and queue the IRP to the current thread to make
  4949. // sure it won't go away until IRP is completed.
  4950. //
  4951. if ((((transmitInfo->Flags & AFD_TF_WORKER_KIND_MASK)
  4952. == AFD_TF_USE_KERNEL_APC) ||
  4953. (((transmitInfo->Flags & AFD_TF_WORKER_KIND_MASK)
  4954. == AFD_TF_USE_DEFAULT_WORKER) &&
  4955. (AfdDefaultTransmitWorker==AFD_TF_USE_KERNEL_APC))) ) {
  4956. //
  4957. // Allocation will occur right before we call the
  4958. // transport, set IRP to null to trigger this.
  4959. //
  4960. irp = NULL;
  4961. }
  4962. }
  4963. else {
  4964. #if AFD_PERF_DBG
  4965. InterlockedIncrement (&AfdFastTfReadFailed);
  4966. #endif
  4967. goto complete;
  4968. }
  4969. }
  4970. //
  4971. // If we read less information than was requested, we must have
  4972. // hit the end of the file. Fail the transmit request, since
  4973. // this can only happen if the caller requested that we send
  4974. // more data than the file currently contains.
  4975. //
  4976. if ( IoStatus->Information < fileWriteLength ) {
  4977. goto complete;
  4978. }
  4979. }
  4980. //
  4981. // We have to rebuild the MDL in the AFD buffer structure to
  4982. // represent exactly the number of bytes we're going to be
  4983. // sending. If the AFD buffer has all the send data, indicate
  4984. // that. If we did MDL file I/O, then chain the file data on
  4985. // to the head MDL.
  4986. //
  4987. if ( fileMdl == NULL ) {
  4988. afdBuffer->Mdl->ByteCount = sendLength.LowPart;
  4989. } else {
  4990. afdBuffer->Mdl->ByteCount = transmitInfo->HeadLength;
  4991. afdBuffer->Mdl->Next = fileMdl;
  4992. }
  4993. //
  4994. // We can have only one transmit file operation on endpoint
  4995. // at a time. Treat is as a state change
  4996. //
  4997. if (AFD_START_STATE_CHANGE (endpoint, endpoint->State)) {
  4998. //
  4999. // Verify state under protection of state change flag
  5000. //
  5001. if (endpoint->State!=AfdEndpointStateConnected) {
  5002. AFD_END_STATE_CHANGE (endpoint);
  5003. goto complete;
  5004. }
  5005. //
  5006. // Save connection to dereference in completion routine.
  5007. //
  5008. afdBuffer->Context = connection;
  5009. if (irp==NULL) {
  5010. //
  5011. // Need to allocate IRP and let the io subsystem queue
  5012. // it to the current thread, so we can run APC upon
  5013. // IRP completion.
  5014. //
  5015. irp = TdiBuildInternalDeviceControlIrp (
  5016. TDI_SEND,
  5017. connection->DeviceObject,
  5018. connection->FileObject,
  5019. NULL,
  5020. &AfdDontCareIoStatus // we will have our completion
  5021. // routine installed in the IRP which will get the
  5022. // status, so we do not care if IO system writes
  5023. // it there for us, but still must provide valid
  5024. // storage to avoid failure.
  5025. );
  5026. if (irp==NULL) {
  5027. //
  5028. // Could not allocate IRP, use worker threads
  5029. //
  5030. irp = afdBuffer->Irp;
  5031. }
  5032. }
  5033. else {
  5034. ASSERT (irp==afdBuffer->Irp);
  5035. }
  5036. //
  5037. // Use the IRP in the AFD buffer structure to give to the TDI
  5038. // provider. Build the TDI send request.
  5039. //
  5040. TdiBuildSend(
  5041. irp,
  5042. connection->DeviceObject,
  5043. connection->FileObject,
  5044. AfdRestartFastTransmitSend,
  5045. afdBuffer,
  5046. afdBuffer->Mdl,
  5047. 0,
  5048. sendLength.LowPart
  5049. );
  5050. IF_DEBUG (TRANSMIT) {
  5051. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5052. "AfdFastTransmit: Starting send for endp-%p,file-%p,"
  5053. "afdBuffer-%p,length-%ld.\n",
  5054. endpoint,fileObject,(PVOID)afdBuffer,sendLength.LowPart));
  5055. }
  5056. //
  5057. // Call the transport to actually perform the send.
  5058. //
  5059. status = IoCallDriver( connection->DeviceObject, irp );
  5060. AFD_END_STATE_CHANGE (endpoint);
  5061. //
  5062. // The fast path succeeded--complete the call. Note that we
  5063. // change the status code from what was returned by the TDI
  5064. // provider into STATUS_SUCCESS. This is because we don't want
  5065. // to complete the IRP with STATUS_PENDING etc.
  5066. //
  5067. if ( NT_SUCCESS(status) ) {
  5068. IoStatus->Information = sendLength.LowPart;
  5069. IoStatus->Status = STATUS_SUCCESS;
  5070. return TRUE;
  5071. }
  5072. else {
  5073. // The restart routine will handle cleanup
  5074. // and we cannot duplicate cleanup in the
  5075. // case of a failure or exception below.
  5076. //
  5077. return FALSE;
  5078. }
  5079. }
  5080. //
  5081. // The call failed for some reason. Fail fast IO.
  5082. //
  5083. complete:
  5084. if ( fileMdl != NULL ) {
  5085. ASSERT (afdBuffer!=NULL);
  5086. status = AfdMdlReadComplete( fileObject, fileMdl, &fileOffset );
  5087. if (!NT_SUCCESS (status)) {
  5088. afdBuffer->Context = connection;
  5089. REFERENCE_CONNECTION (connection);
  5090. ASSERT (afdBuffer->FileObject==fileObject);
  5091. ASSERT (afdBuffer->Mdl->Next==fileMdl);
  5092. ASSERT (afdBuffer->FileOffset.QuadPart==fileOffset.QuadPart);
  5093. AfdLRMdlReadComplete (&afdBuffer->Header);
  5094. afdBuffer = NULL;
  5095. fileObject = NULL;
  5096. }
  5097. }
  5098. if ( fileObject != NULL ) {
  5099. ObDereferenceObject( fileObject );
  5100. AfdRecordFileDeref();
  5101. }
  5102. if ( afdBuffer != NULL ) {
  5103. ASSERT ((irp==NULL) || (irp==afdBuffer->Irp));
  5104. afdBuffer->Mdl->Next = NULL;
  5105. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  5106. AfdReturnBuffer( &afdBuffer->Header, connection->OwningProcess );
  5107. }
  5108. if ( sendCountersUpdated ) {
  5109. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  5110. connection->VcBufferredSendBytes -= sendLength.LowPart;
  5111. connection->VcBufferredSendCount -= 1;
  5112. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  5113. DEREFERENCE_CONNECTION (connection);
  5114. }
  5115. return FALSE;
  5116. } // AfdFastTransmitFile
  5117. NTSTATUS
  5118. AfdRestartFastTransmitSend (
  5119. IN PDEVICE_OBJECT DeviceObject,
  5120. IN PIRP Irp,
  5121. IN PVOID Context
  5122. )
  5123. /*++
  5124. Routine Description:
  5125. This is the completion routine for fast transmit send IRPs.
  5126. It initiates the completion of the request.
  5127. Arguments:
  5128. DeviceObject - ignored.
  5129. Irp - the send IRP that is completing.
  5130. Context - a pointer to the AfdBuffer structure with the buffer that
  5131. was sent.
  5132. Return Value:
  5133. STATUS_MORE_PROCESSING_REQUIRED which indicates to the I/O system
  5134. that it should stop completion processing of this IRP. User request
  5135. has already been completed on the fast path, we just free resources here.
  5136. --*/
  5137. {
  5138. PAFD_BUFFER afdBuffer = Context;
  5139. PAFD_CONNECTION connection = afdBuffer->Context;
  5140. NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
  5141. IF_DEBUG (TRANSMIT) {
  5142. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5143. "AfdRestartFastTransmitSend: Completing send for file-%p,"
  5144. "afdBuffer-%p,status-%lx.\n",
  5145. afdBuffer->FileObject,(PVOID)afdBuffer,Irp->IoStatus.Status));
  5146. }
  5147. AfdProcessBufferSend (connection, Irp);
  5148. //
  5149. // If file object is not NULL we need to
  5150. // return MDL back to file system driver/cache
  5151. //
  5152. if (afdBuffer->FileObject!=NULL) {
  5153. //
  5154. // If we used a separate IRP, then
  5155. // the caller requested that we do processing
  5156. // inside kernel APC, otherwise, we are using
  5157. // system worker threads.
  5158. //
  5159. if (afdBuffer->Irp!=Irp) {
  5160. //
  5161. // The IRP is owned by IO subsystem.
  5162. // We must let it complete and free the IRP, hence
  5163. // return STATUS_SUCCESS and remove MDL field as IO
  5164. // subsytem cannot handle non-paged pool memory in MDL
  5165. //
  5166. status = STATUS_SUCCESS;
  5167. Irp->MdlAddress = NULL;
  5168. //
  5169. // If IRP was not cancelled, attempt to initialize and queue APC
  5170. // Otherwise, the thread is probably exiting and we won't be
  5171. // able to queue apc anyway.
  5172. //
  5173. if (!Irp->Cancel) {
  5174. ASSERT (afdBuffer->BufferLength>=sizeof(KAPC));
  5175. KeInitializeApc (afdBuffer->Buffer,
  5176. PsGetThreadTcb (Irp->Tail.Overlay.Thread),
  5177. Irp->ApcEnvironment,
  5178. AfdFastTransmitApcKernelRoutine,
  5179. AfdFastTransmitApcRundownRoutine,
  5180. (PKNORMAL_ROUTINE)-1,
  5181. KernelMode,
  5182. NULL
  5183. );
  5184. if (KeInsertQueueApc (afdBuffer->Buffer,
  5185. afdBuffer,
  5186. afdBuffer->FileObject,
  5187. AfdPriorityBoost)) {
  5188. //
  5189. // Success, we are done.
  5190. //
  5191. goto exit;
  5192. }
  5193. }
  5194. //
  5195. // Can't queue APC, revert to system worker threads
  5196. //
  5197. }
  5198. ASSERT (afdBuffer->BufferLength>=sizeof(WORK_QUEUE_ITEM));
  5199. ExInitializeWorkItem (
  5200. (PWORK_QUEUE_ITEM)afdBuffer->Buffer,
  5201. AfdDoMdlReadComplete,
  5202. afdBuffer
  5203. );
  5204. ExQueueWorkItem (afdBuffer->Buffer, DelayedWorkQueue);
  5205. }
  5206. else {
  5207. ASSERT (afdBuffer->Irp==Irp);
  5208. ASSERT (afdBuffer->Mdl->Next == NULL);
  5209. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  5210. AfdReturnBuffer( &afdBuffer->Header, connection->OwningProcess );
  5211. DEREFERENCE_CONNECTION (connection);
  5212. }
  5213. exit:
  5214. return status;
  5215. }
  5216. VOID
  5217. AfdFastTransmitApcKernelRoutine (
  5218. IN struct _KAPC *Apc,
  5219. IN OUT PKNORMAL_ROUTINE *NormalRoutine,
  5220. IN OUT PVOID *NormalContext,
  5221. IN OUT PVOID *SystemArgument1,
  5222. IN OUT PVOID *SystemArgument2
  5223. )
  5224. /*++
  5225. Routine Description:
  5226. Special kernel apc routine. Executed in the context of
  5227. the target thread at APC_LEVEL
  5228. Arguments:
  5229. NormalRoutine - pointer containing address of normal routine (it will
  5230. be NULL for special kernel APC and not NULL for normal
  5231. kernel APC)
  5232. SystemArgument1 - pointer to the address of worker routine to execute
  5233. SyetemArgument2 - pointer to the argument to pass to worker routine
  5234. Return Value:
  5235. None.
  5236. --*/
  5237. {
  5238. PAFD_BUFFER afdBuffer;
  5239. PAGED_CODE ();
  5240. #if DBG
  5241. try {
  5242. #endif
  5243. afdBuffer = *SystemArgument1;
  5244. ASSERT (Apc==afdBuffer->Buffer);
  5245. ASSERT (afdBuffer->FileObject==*SystemArgument2);
  5246. //
  5247. // Normal APC, but we are requested to run in its special
  5248. // routine which avoids raising and lowering IRQL
  5249. //
  5250. ASSERT (*NormalRoutine==(PKNORMAL_ROUTINE)-1);
  5251. *NormalRoutine = NULL;
  5252. AfdDoMdlReadComplete (afdBuffer);
  5253. #if DBG
  5254. }
  5255. except (AfdApcExceptionFilter (GetExceptionInformation (),
  5256. __FILE__,
  5257. __LINE__)) {
  5258. DbgBreakPoint ();
  5259. }
  5260. #endif
  5261. }
  5262. VOID
  5263. AfdFastTransmitApcRundownRoutine (
  5264. IN struct _KAPC *Apc
  5265. )
  5266. /*++
  5267. Routine Description:
  5268. APC rundown routine. Executed if APC cannot be delivered for
  5269. some reason (thread exiting).
  5270. We just fall back to system threads to execute the worker
  5271. Arguments:
  5272. Apc - APC structure
  5273. Return Value:
  5274. None.
  5275. --*/
  5276. {
  5277. PAFD_BUFFER afdBuffer;
  5278. PAGED_CODE ();
  5279. #if DBG
  5280. try {
  5281. #endif
  5282. afdBuffer = Apc->SystemArgument1;
  5283. ASSERT (Apc==afdBuffer->Buffer);
  5284. ASSERT (afdBuffer->FileObject==Apc->SystemArgument2);
  5285. //
  5286. // APC could not be run, revert to system worker thread
  5287. //
  5288. ExInitializeWorkItem (
  5289. (PWORK_QUEUE_ITEM)afdBuffer->Buffer,
  5290. AfdDoMdlReadComplete,
  5291. afdBuffer
  5292. );
  5293. ExQueueWorkItem (afdBuffer->Buffer, DelayedWorkQueue);
  5294. #if DBG
  5295. }
  5296. except (AfdApcExceptionFilter (GetExceptionInformation (),
  5297. __FILE__,
  5298. __LINE__)) {
  5299. DbgBreakPoint ();
  5300. }
  5301. #endif
  5302. }
  5303. VOID
  5304. AfdDoMdlReadComplete (
  5305. PVOID Context
  5306. )
  5307. {
  5308. PAFD_BUFFER afdBuffer = Context;
  5309. PAFD_CONNECTION connection = afdBuffer->Context;
  5310. NTSTATUS status;
  5311. PAGED_CODE ();
  5312. //
  5313. // Return mdl to the file system
  5314. //
  5315. status = AfdMdlReadComplete(
  5316. afdBuffer->FileObject,
  5317. afdBuffer->Mdl->Next,
  5318. &afdBuffer->Irp->Overlay.AllocationSize
  5319. );
  5320. if (NT_SUCCESS (status)) {
  5321. //
  5322. // Release file object reference (the AfdMdlReadComplete makes its own
  5323. // reference if it needs to return MDL asynchronously.
  5324. //
  5325. ObDereferenceObject( afdBuffer->FileObject );
  5326. AfdRecordFileDeref();
  5327. afdBuffer->Mdl->Next = NULL;
  5328. afdBuffer->Mdl->ByteCount = afdBuffer->BufferLength;
  5329. AfdReturnBuffer( &afdBuffer->Header, connection->OwningProcess );
  5330. DEREFERENCE_CONNECTION (connection);
  5331. }
  5332. else {
  5333. AfdLRMdlReadComplete (&afdBuffer->Header);
  5334. }
  5335. }
  5336. NTSTATUS
  5337. FASTCALL
  5338. AfdTransmitFile (
  5339. IN PIRP Irp,
  5340. IN PIO_STACK_LOCATION IrpSp
  5341. )
  5342. /*++
  5343. Routine Description:
  5344. Initial entrypoint for handling transmit file IRPs. This routine
  5345. verifies parameters, initializes data structures to be used for
  5346. the request, and initiates the I/O.
  5347. Arguments:
  5348. Irp - a pointer to a transmit file IRP.
  5349. IrpSp - Our stack location for this IRP.
  5350. Return Value:
  5351. STATUS_PENDING if the request was initiated successfully, or a
  5352. failure status code if there was an error.
  5353. --*/
  5354. {
  5355. PAFD_ENDPOINT endpoint;
  5356. NTSTATUS status;
  5357. AFD_TRANSMIT_FILE_INFO params;
  5358. PAFD_TPACKETS_INFO_INTERNAL tpInfo = NULL;
  5359. PAFD_TRANSMIT_PACKETS_ELEMENT pel;
  5360. BOOLEAN irpQueued;
  5361. PAGED_CODE ();
  5362. //
  5363. // Initial request validity checks: is the endpoint connected, is
  5364. // the input buffer large enough, etc.
  5365. //
  5366. endpoint = IrpSp->FileObject->FsContext;
  5367. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  5368. //
  5369. // Special hack to let the user mode dll know that it
  5370. // should try SAN provider instead.
  5371. //
  5372. if (IS_SAN_ENDPOINT (endpoint)) {
  5373. status = STATUS_INVALID_PARAMETER_12;
  5374. goto complete;
  5375. }
  5376. #ifdef _WIN64
  5377. if (IoIs32bitProcess (Irp)) {
  5378. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  5379. sizeof(AFD_TRANSMIT_FILE_INFO32) ) {
  5380. status = STATUS_INVALID_PARAMETER;
  5381. goto complete;
  5382. }
  5383. }
  5384. else
  5385. #endif _WIN64
  5386. {
  5387. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  5388. sizeof(AFD_TRANSMIT_FILE_INFO) ) {
  5389. status = STATUS_INVALID_PARAMETER;
  5390. goto complete;
  5391. }
  5392. }
  5393. //
  5394. // Because we're using type 3 (neither) I/O for this IRP, the I/O
  5395. // system does no verification on the user buffer. Therefore, we
  5396. // must manually check it for validity inside a try-except block.
  5397. // We also leverage the try-except to validate and lock down the
  5398. // head and/or tail buffers specified by the caller.
  5399. //
  5400. try {
  5401. #ifdef _WIN64
  5402. if (IoIs32bitProcess (Irp)) {
  5403. PAFD_TRANSMIT_FILE_INFO32 pInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  5404. if( Irp->RequestorMode != KernelMode ) {
  5405. //
  5406. // Validate the control buffer.
  5407. //
  5408. ProbeForRead(
  5409. pInfo,
  5410. sizeof(AFD_TRANSMIT_FILE_INFO32),
  5411. PROBE_ALIGNMENT32 (AFD_TRANSMIT_FILE_INFO32)
  5412. );
  5413. }
  5414. params.Offset = pInfo->Offset;
  5415. params.WriteLength = pInfo->WriteLength;
  5416. params.SendPacketLength = pInfo->SendPacketLength;
  5417. params.FileHandle = pInfo->FileHandle;
  5418. params.Head = pInfo->Head;
  5419. params.HeadLength = pInfo->HeadLength;
  5420. params.Tail = pInfo->Tail;
  5421. params.TailLength = pInfo->TailLength;
  5422. params.Flags = pInfo->Flags;
  5423. }
  5424. else
  5425. #endif _WIN64
  5426. {
  5427. if( Irp->RequestorMode != KernelMode ) {
  5428. //
  5429. // Validate the control buffer.
  5430. //
  5431. ProbeForRead(
  5432. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  5433. sizeof(AFD_TRANSMIT_FILE_INFO),
  5434. PROBE_ALIGNMENT (AFD_TRANSMIT_FILE_INFO)
  5435. );
  5436. }
  5437. params = *((PAFD_TRANSMIT_FILE_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  5438. }
  5439. //
  5440. // Validate any flags specified in the request.
  5441. // and make sure that file offset is positive (of course if file is specified)
  5442. //
  5443. if ( ((params.Flags &
  5444. ~(AFD_TF_WRITE_BEHIND | AFD_TF_DISCONNECT | AFD_TF_REUSE_SOCKET | AFD_TF_WORKER_KIND_MASK) )
  5445. != 0 ) ||
  5446. ((params.Flags & AFD_TF_WORKER_KIND_MASK) == AFD_TF_WORKER_KIND_MASK) ||
  5447. (params.FileHandle!=NULL && params.Offset.QuadPart<0)){
  5448. status = STATUS_INVALID_PARAMETER;
  5449. goto complete;
  5450. }
  5451. //
  5452. // If transmit worker is not specified, use system default setting
  5453. //
  5454. if ((params.Flags & AFD_TF_WORKER_KIND_MASK)==AFD_TF_USE_DEFAULT_WORKER) {
  5455. params.Flags |= AfdDefaultTransmitWorker;
  5456. }
  5457. tpInfo = AfdGetTpInfo (3);
  5458. if (tpInfo==NULL) {
  5459. status = STATUS_INSUFFICIENT_RESOURCES;
  5460. goto complete;
  5461. }
  5462. tpInfo->ElementCount = 0;
  5463. tpInfo->SendPacketLength = params.SendPacketLength;
  5464. if (tpInfo->SendPacketLength==0)
  5465. tpInfo->SendPacketLength = AfdTransmitIoLength;
  5466. //
  5467. // If the caller specified head and/or tail buffers, probe and
  5468. // lock the buffers so that we have MDLs we can use to send the
  5469. // buffers.
  5470. //
  5471. if ( params.HeadLength > 0 ) {
  5472. pel = &tpInfo->ElementArray[tpInfo->ElementCount++];
  5473. pel->Buffer = params.Head;
  5474. pel->Length = params.HeadLength;
  5475. pel->Flags = TP_MEMORY;
  5476. if (params.Flags & AFD_TF_USE_SYSTEM_THREAD) {
  5477. pel->Flags |= TP_MDL;
  5478. pel->Mdl = IoAllocateMdl(
  5479. params.Head,
  5480. params.HeadLength,
  5481. FALSE, // SecondaryBuffer
  5482. TRUE, // ChargeQuota
  5483. NULL // Irp
  5484. );
  5485. if ( pel->Mdl == NULL ) {
  5486. status = STATUS_INSUFFICIENT_RESOURCES;
  5487. goto complete;
  5488. }
  5489. MmProbeAndLockPages( pel->Mdl, Irp->RequestorMode, IoReadAccess );
  5490. }
  5491. }
  5492. if (params.FileHandle!=NULL) {
  5493. pel = &tpInfo->ElementArray[tpInfo->ElementCount++];
  5494. pel->Flags = TP_FILE;
  5495. pel->FileOffset = params.Offset;
  5496. //
  5497. // Get a referenced pointer to the file object for the file that
  5498. // we're going to transmit. This call will fail if the file handle
  5499. // specified by the caller is invalid.
  5500. //
  5501. status = ObReferenceObjectByHandle(
  5502. params.FileHandle,
  5503. FILE_READ_DATA,
  5504. *IoFileObjectType,
  5505. Irp->RequestorMode,
  5506. (PVOID *)&pel->FileObject,
  5507. NULL
  5508. );
  5509. if ( !NT_SUCCESS(status) ) {
  5510. //
  5511. // Unbump element count, so that uninitialied memory
  5512. // is NOT improperly dereferenced in cleanup.
  5513. //
  5514. tpInfo->ElementCount -= 1;
  5515. //
  5516. // Tell the caller that we encountered an error
  5517. // when accessing file not socket.
  5518. //
  5519. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>=sizeof (BOOLEAN)) {
  5520. if (Irp->RequestorMode != KernelMode) {
  5521. ProbeAndWriteBoolean ((BOOLEAN *)Irp->UserBuffer, TRUE);
  5522. }
  5523. else {
  5524. *((BOOLEAN *)Irp->UserBuffer) = TRUE;
  5525. }
  5526. }
  5527. goto complete;
  5528. }
  5529. AfdRecordFileRef();
  5530. //
  5531. // Use pre-allocated buffers by default when
  5532. // file is not cached
  5533. //
  5534. if (params.SendPacketLength==0 && !AFD_USE_CACHE(pel->FileObject)) {
  5535. tpInfo->SendPacketLength = AfdLargeBufferSize;
  5536. }
  5537. if ( (pel->FileObject->Flags & FO_SYNCHRONOUS_IO) &&
  5538. (pel->FileOffset.QuadPart == 0) ) {
  5539. //
  5540. // Use current offset if file is opened syncronously
  5541. // and offset is not specified.
  5542. //
  5543. pel->FileOffset = pel->FileObject->CurrentByteOffset;
  5544. }
  5545. if ( params.WriteLength.QuadPart == 0 ) {
  5546. //
  5547. // Length was not specified, figure out the
  5548. // size of the entire file
  5549. //
  5550. FILE_STANDARD_INFORMATION fileInfo;
  5551. IO_STATUS_BLOCK ioStatusBlock;
  5552. status = ZwQueryInformationFile(
  5553. params.FileHandle,
  5554. &ioStatusBlock,
  5555. &fileInfo,
  5556. sizeof(fileInfo),
  5557. FileStandardInformation
  5558. );
  5559. if ( !NT_SUCCESS(status) ) {
  5560. //
  5561. // Tell the caller that we encountered an error
  5562. // when accessing file not socket.
  5563. //
  5564. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength>=sizeof (BOOLEAN)) {
  5565. if (Irp->RequestorMode != KernelMode) {
  5566. ProbeAndWriteBoolean ((BOOLEAN *)Irp->UserBuffer, TRUE);
  5567. }
  5568. else {
  5569. *((BOOLEAN *)Irp->UserBuffer) = TRUE;
  5570. }
  5571. }
  5572. goto complete;
  5573. }
  5574. //
  5575. // Make sure that offset is within the file
  5576. //
  5577. if (pel->FileOffset.QuadPart<0
  5578. ||
  5579. pel->FileOffset.QuadPart>fileInfo.EndOfFile.QuadPart
  5580. ||
  5581. (fileInfo.EndOfFile.QuadPart
  5582. - pel->FileOffset.QuadPart>MAXLONG)) {
  5583. status = STATUS_INVALID_PARAMETER;
  5584. goto complete;
  5585. }
  5586. pel->Length = (ULONG)(fileInfo.EndOfFile.QuadPart - pel->FileOffset.QuadPart);
  5587. }
  5588. else if (params.WriteLength.QuadPart<=MAXLONG &&
  5589. pel->FileOffset.QuadPart>=0) {
  5590. pel->Length = (ULONG)params.WriteLength.QuadPart;
  5591. }
  5592. else {
  5593. status = STATUS_INVALID_PARAMETER;
  5594. goto complete;
  5595. }
  5596. }
  5597. if ( params.TailLength > 0 ) {
  5598. pel = &tpInfo->ElementArray[tpInfo->ElementCount++];
  5599. pel->Buffer = params.Tail;
  5600. pel->Length = params.TailLength;
  5601. pel->Flags = TP_MEMORY;
  5602. if (params.Flags & AFD_TF_USE_SYSTEM_THREAD) {
  5603. pel->Flags |= TP_MDL;
  5604. pel->Mdl = IoAllocateMdl(
  5605. params.Tail,
  5606. params.TailLength,
  5607. FALSE, // SecondaryBuffer
  5608. TRUE, // ChargeQuota
  5609. NULL // Irp
  5610. );
  5611. if ( pel->Mdl == NULL ) {
  5612. status = STATUS_INSUFFICIENT_RESOURCES;
  5613. goto complete;
  5614. }
  5615. MmProbeAndLockPages( pel->Mdl, Irp->RequestorMode, IoReadAccess );
  5616. }
  5617. }
  5618. IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags = params.Flags;
  5619. } except( AFD_EXCEPTION_FILTER(&status) ) {
  5620. goto complete;
  5621. }
  5622. if (!AFD_START_STATE_CHANGE (endpoint, endpoint->State)) {
  5623. status = STATUS_INVALID_CONNECTION;
  5624. goto complete;
  5625. }
  5626. if ( endpoint->Type != AfdBlockTypeVcConnecting ||
  5627. endpoint->State != AfdEndpointStateConnected ) {
  5628. status = STATUS_INVALID_CONNECTION;
  5629. goto complete_state_change;
  5630. }
  5631. //
  5632. // Connection endpoint, get connection file object and device
  5633. //
  5634. tpInfo->TdiFileObject = endpoint->Common.VcConnecting.Connection->FileObject;
  5635. tpInfo->TdiDeviceObject = endpoint->Common.VcConnecting.Connection->DeviceObject;
  5636. //
  5637. // Setting AFD_TF_REUSE_SOCKET implies that a disconnect is desired.
  5638. // Also, setting this flag means that no more I/O is legal on the
  5639. // endpoint until the transmit request has been completed, so
  5640. // set up the endpoint's state so that I/O fails.
  5641. //
  5642. if ( (IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_REUSE_SOCKET) != 0 ) {
  5643. IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags |= AFD_TF_DISCONNECT;
  5644. endpoint->State = AfdEndpointStateTransmitClosing;
  5645. }
  5646. UPDATE_TPACKETS2 (Irp, "Connection object handle: %lx",
  5647. HandleToUlong(endpoint->Common.VcConnecting.Connection->Handle));
  5648. //
  5649. // Save tpacket info in the IRP
  5650. //
  5651. Irp->AssociatedIrp.SystemBuffer = tpInfo;
  5652. //
  5653. // Clear the Flink in the IRP to indicate this IRP is not queued.
  5654. // Blink is cleared to indicate that IRP was counted towards
  5655. // active maximum.
  5656. //
  5657. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  5658. Irp->Tail.Overlay.ListEntry.Blink = NULL;
  5659. //
  5660. // Initialize the IRP result fields
  5661. //
  5662. Irp->IoStatus.Status = STATUS_SUCCESS;
  5663. Irp->IoStatus.Information = 0;
  5664. //
  5665. // We are going to pend this IRP
  5666. //
  5667. IoMarkIrpPending( Irp );
  5668. //
  5669. // Initialize queuing and state information.
  5670. //
  5671. InitializeListHead (&AFD_GET_TPIC(Irp)->EndpQueueEntry);
  5672. AFD_GET_TPIC(Irp)->ReferenceCount = 1;
  5673. AFD_GET_TPIC(Irp)->StateFlags = AFD_TP_WORKER_SCHEDULED;
  5674. irpQueued = (InterlockedCompareExchangePointer ((PVOID *)&endpoint->Irp,
  5675. Irp,
  5676. NULL)!=NULL) &&
  5677. AfdEnqueueTPacketsIrp (endpoint, Irp);
  5678. //
  5679. // If disconnect is not specified, end state change.
  5680. // This will permit queuing of another transmit IRP
  5681. //
  5682. if (!(IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags & AFD_TF_DISCONNECT)) {
  5683. AFD_END_STATE_CHANGE (endpoint);
  5684. }
  5685. IoSetCancelRoutine( Irp, AfdCancelTPackets );
  5686. //
  5687. // Check to see if this Irp has been cancelled.
  5688. //
  5689. if ( !Irp->Cancel ) {
  5690. if (irpQueued) {
  5691. DEREFERENCE_TPACKETS (Irp);
  5692. }
  5693. else {
  5694. //
  5695. // Determine if we can really start this file transmit now. If we've
  5696. // exceeded the configured maximum number of active TransmitFile/Packets
  5697. // requests, then append this IRP to the TransmitFile/Packets queue and set
  5698. // a flag in the transmit info structure to indicate that this IRP
  5699. // is queued.
  5700. //
  5701. if( AfdMaxActiveTransmitFileCount == 0 || !AfdQueueTransmit (Irp)) {
  5702. //
  5703. // Start I/O
  5704. //
  5705. AfdTPacketsWorker (Irp);
  5706. }
  5707. }
  5708. }
  5709. else {
  5710. //
  5711. // Abort the request
  5712. // Note that neither cancel nor endpoint cleanup can complete
  5713. // the IRP since we hold the reference to the tpInfo structure.
  5714. //
  5715. AfdAbortTPackets (Irp, STATUS_CANCELLED);
  5716. //
  5717. // Remove the initial reference and force completion.
  5718. //
  5719. DEREFERENCE_TPACKETS (Irp);
  5720. }
  5721. return STATUS_PENDING;
  5722. complete_state_change:
  5723. ASSERT ( tpInfo != NULL );
  5724. ASSERT ( endpoint->Irp != Irp );
  5725. AFD_END_STATE_CHANGE (endpoint);
  5726. complete:
  5727. if (tpInfo!=NULL) {
  5728. AfdReturnTpInfo (tpInfo);
  5729. }
  5730. IF_DEBUG (TRANSMIT) {
  5731. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5732. "AfdTransmitPackets: Failing Irp-%p,endpoint-%p,status-%lx\n",
  5733. Irp,endpoint,status));
  5734. }
  5735. //
  5736. // Complete the request.
  5737. //
  5738. Irp->IoStatus.Information = 0;
  5739. Irp->IoStatus.Status = status;
  5740. IoCompleteRequest( Irp, 0 );
  5741. return status;
  5742. } // AfdTransmitFile
  5743. NTSTATUS
  5744. FASTCALL
  5745. AfdSuperDisconnect (
  5746. IN PIRP Irp,
  5747. IN PIO_STACK_LOCATION IrpSp
  5748. )
  5749. /*++
  5750. Routine Description:
  5751. Initial entrypoint for handling transmit file IRPs. This routine
  5752. verifies parameters, initializes data structures to be used for
  5753. the request, and initiates the I/O.
  5754. Arguments:
  5755. Irp - a pointer to a transmit file IRP.
  5756. IrpSp - Our stack location for this IRP.
  5757. Return Value:
  5758. STATUS_PENDING if the request was initiated successfully, or a
  5759. failure status code if there was an error.
  5760. --*/
  5761. {
  5762. PAFD_ENDPOINT endpoint;
  5763. NTSTATUS status;
  5764. AFD_SUPER_DISCONNECT_INFO params;
  5765. BOOLEAN irpQueued;
  5766. PAGED_CODE ();
  5767. //
  5768. // Initial request validity checks: is the endpoint connected, is
  5769. // the input buffer large enough, etc.
  5770. //
  5771. endpoint = IrpSp->FileObject->FsContext;
  5772. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  5773. //
  5774. // Special hack to let the user mode dll know that it
  5775. // should try SAN provider instead.
  5776. //
  5777. if (IS_SAN_ENDPOINT (endpoint)) {
  5778. status = STATUS_INVALID_PARAMETER_12;
  5779. goto complete;
  5780. }
  5781. //
  5782. // Because we're using type 3 (neither) I/O for this IRP, the I/O
  5783. // system does no verification on the user buffer. Therefore, we
  5784. // must manually check it for validity inside a try-except block.
  5785. // We also leverage the try-except to validate and lock down the
  5786. // head and/or tail buffers specified by the caller.
  5787. //
  5788. try {
  5789. #ifdef _WIN64
  5790. if (IoIs32bitProcess (Irp)) {
  5791. PAFD_SUPER_DISCONNECT_INFO32 pInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  5792. if( Irp->RequestorMode != KernelMode ) {
  5793. //
  5794. // Validate the control buffer.
  5795. //
  5796. ProbeForRead(
  5797. pInfo,
  5798. sizeof(AFD_SUPER_DISCONNECT_INFO32),
  5799. PROBE_ALIGNMENT32 (AFD_SUPER_DISCONNECT_INFO32)
  5800. );
  5801. }
  5802. params.Flags = ((PAFD_SUPER_DISCONNECT_INFO32)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)->Flags;
  5803. }
  5804. else
  5805. #endif _WIN64
  5806. {
  5807. if( Irp->RequestorMode != KernelMode ) {
  5808. //
  5809. // Validate the control buffer.
  5810. //
  5811. ProbeForRead(
  5812. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  5813. sizeof(AFD_SUPER_DISCONNECT_INFO),
  5814. PROBE_ALIGNMENT (AFD_SUPER_DISCONNECT_INFO)
  5815. );
  5816. }
  5817. params = *((PAFD_SUPER_DISCONNECT_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  5818. }
  5819. //
  5820. // Validate any flags specified in the request.
  5821. // and make sure that file offset is positive (of course if file is specified)
  5822. //
  5823. if ( (params.Flags & (~AFD_TF_REUSE_SOCKET)) != 0 ){
  5824. status = STATUS_INVALID_PARAMETER;
  5825. goto complete;
  5826. }
  5827. } except( AFD_EXCEPTION_FILTER(&status) ) {
  5828. goto complete;
  5829. }
  5830. //
  5831. // Store disconnect parameters/flags in the IRP.
  5832. //
  5833. IrpSp->Parameters.AfdTPacketsInfo.AfdTPacketsFlags =
  5834. params.Flags |
  5835. AFD_TF_DISCONNECT | // Implied in the API
  5836. AFD_TF_USE_KERNEL_APC; // Just need to start when
  5837. // in the endpoint queue.
  5838. if (!AFD_START_STATE_CHANGE (endpoint, endpoint->State)) {
  5839. status = STATUS_INVALID_CONNECTION;
  5840. goto complete;
  5841. }
  5842. if ( endpoint->Type != AfdBlockTypeVcConnecting ||
  5843. endpoint->State != AfdEndpointStateConnected ) {
  5844. status = STATUS_INVALID_CONNECTION;
  5845. goto complete_state_change;
  5846. }
  5847. //
  5848. // Setting AFD_TF_REUSE_SOCKET implies that a disconnect is desired.
  5849. // Also, setting this flag means that no more I/O is legal on the
  5850. // endpoint until the transmit request has been completed, so
  5851. // set up the endpoint's state so that I/O fails.
  5852. //
  5853. if ( (params.Flags & AFD_TF_REUSE_SOCKET) != 0 ) {
  5854. endpoint->State = AfdEndpointStateTransmitClosing;
  5855. }
  5856. //
  5857. // Save tpacket info in the IRP
  5858. //
  5859. Irp->AssociatedIrp.SystemBuffer = NULL;
  5860. //
  5861. // Clear the Flink in the IRP to indicate this IRP is not queued.
  5862. // Blink is set to indicate that IRP was not counted towards active maximum.
  5863. // (we never count disconnect ex IRPs, event on workstation).
  5864. //
  5865. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  5866. Irp->Tail.Overlay.ListEntry.Blink = (PVOID)1;
  5867. //
  5868. // Initialize the IRP result fields
  5869. //
  5870. Irp->IoStatus.Status = STATUS_SUCCESS;
  5871. Irp->IoStatus.Information = 0;
  5872. //
  5873. // We are going to pend this IRP
  5874. //
  5875. IoMarkIrpPending( Irp );
  5876. InitializeListHead (&AFD_GET_TPIC(Irp)->EndpQueueEntry);
  5877. AFD_GET_TPIC(Irp)->ReferenceCount = 1;
  5878. AFD_GET_TPIC(Irp)->StateFlags = AFD_TP_WORKER_SCHEDULED;
  5879. irpQueued = (InterlockedCompareExchangePointer ((PVOID *)&endpoint->Irp,
  5880. Irp,
  5881. NULL)!=NULL) &&
  5882. AfdEnqueueTPacketsIrp (endpoint, Irp);
  5883. IoSetCancelRoutine( Irp, AfdCancelTPackets );
  5884. //
  5885. // Check to see if this Irp has been cancelled.
  5886. //
  5887. if ( !Irp->Cancel ) {
  5888. if (irpQueued) {
  5889. DEREFERENCE_TPACKETS (Irp);
  5890. }
  5891. else {
  5892. //
  5893. // Start I/O
  5894. //
  5895. AfdPerformSuperDisconnect (Irp);
  5896. }
  5897. }
  5898. else {
  5899. //
  5900. // Abort the request
  5901. // Note that neither cancel nor endpoint cleanup can complete
  5902. // the IRP since we hold the reference to the tpInfo structure.
  5903. //
  5904. AfdAbortTPackets (Irp, STATUS_CANCELLED);
  5905. //
  5906. // Remove the initial reference and force completion.
  5907. //
  5908. DEREFERENCE_TPACKETS (Irp);
  5909. }
  5910. return STATUS_PENDING;
  5911. complete_state_change:
  5912. ASSERT ( endpoint->Irp != Irp );
  5913. AFD_END_STATE_CHANGE (endpoint);
  5914. complete:
  5915. IF_DEBUG (TRANSMIT) {
  5916. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5917. "AfdSuperDisconnect: Failing Irp-%p,endpoint-%p,status-%lx\n",
  5918. Irp,endpoint,status));
  5919. }
  5920. //
  5921. // Complete the request.
  5922. //
  5923. Irp->IoStatus.Information = 0;
  5924. Irp->IoStatus.Status = status;
  5925. IoCompleteRequest( Irp, 0 );
  5926. return status;
  5927. } // AfdSuperDisconnect
  5928. VOID
  5929. AfdPerformSuperDisconnect (
  5930. PIRP TpIrp
  5931. )
  5932. /*++
  5933. Routine Description:
  5934. DisconnectEx engine
  5935. Arguments:
  5936. TpIrp - pointer to TransmitPackets Irp for the request
  5937. Return Value:
  5938. None.
  5939. --*/
  5940. {
  5941. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (TpIrp);
  5942. PAFD_ENDPOINT endpoint = irpSp->FileObject->FsContext;
  5943. NTSTATUS status;
  5944. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  5945. status = AfdBeginDisconnect(
  5946. endpoint,
  5947. NULL,
  5948. NULL
  5949. );
  5950. if (NT_SUCCESS (status)) {
  5951. IF_DEBUG (TRANSMIT) {
  5952. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5953. "AfdSuperDisconnectWorker: Initiated disconnect, tpIrp-%p,status-%lx\n",
  5954. TpIrp, status));
  5955. }
  5956. }
  5957. else {
  5958. //
  5959. // Disconnect failed, we'll have to abort below.
  5960. //
  5961. IF_DEBUG (TRANSMIT) {
  5962. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  5963. "AfdSuperDisconnectWorker: TpInfo-%p, begin discon failed: %lx\n",
  5964. TpIrp, status));
  5965. }
  5966. AfdAbortTPackets (TpIrp, status);
  5967. }
  5968. DEREFERENCE_TPACKETS (TpIrp);
  5969. }