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

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