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

2908 lines
73 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. Read.c
  5. Abstract:
  6. This module implements support for NtReadFile for the
  7. NetWare redirector called by the dispatch driver.
  8. Author:
  9. Colin Watson [ColinW] 07-Apr-1993
  10. Revision History:
  11. --*/
  12. #include "Procs.h"
  13. #ifdef NWDBG
  14. #include <stdlib.h> // rand()
  15. #endif
  16. //
  17. // The local debug trace level
  18. //
  19. #define Dbg (DEBUG_TRACE_READ)
  20. #define SIZE_ADJUST( ic ) \
  21. ( sizeof( ULONG ) + sizeof( ULONG ) + ( ic->Specific.Read.FileOffset & 0x03 ) )
  22. //
  23. // Local procedure prototypes
  24. //
  25. NTSTATUS
  26. NwCommonRead (
  27. IN PIRP_CONTEXT IrpContext
  28. );
  29. NTSTATUS
  30. ReadNcp(
  31. PIRP_CONTEXT IrpContext
  32. );
  33. NTSTATUS
  34. ReadNcpCallback (
  35. IN PIRP_CONTEXT IrpContext,
  36. IN ULONG BytesAvailable,
  37. IN PUCHAR Response
  38. );
  39. VOID
  40. BuildReadNcp(
  41. PIRP_CONTEXT IrpContext,
  42. ULONG FileOffset,
  43. USHORT Length
  44. );
  45. NTSTATUS
  46. ParseReadResponse(
  47. PIRP_CONTEXT IrpContext,
  48. PNCP_READ_RESPONSE Response,
  49. ULONG BytesAvailable,
  50. PUSHORT Length
  51. );
  52. NTSTATUS
  53. BurstRead(
  54. PIRP_CONTEXT IrpContext
  55. );
  56. VOID
  57. BuildBurstReadRequest(
  58. IN PIRP_CONTEXT IrpContext,
  59. IN ULONG Handle,
  60. IN ULONG FileOffset,
  61. IN ULONG Length
  62. );
  63. NTSTATUS
  64. BurstReadCallback (
  65. IN PIRP_CONTEXT IrpContext,
  66. IN ULONG BytesAvailable,
  67. IN PUCHAR Response
  68. );
  69. VOID
  70. RecordPacketReceipt(
  71. IN OUT PIRP_CONTEXT IrpContext,
  72. IN PVOID ReadData,
  73. IN ULONG DataOffset,
  74. IN USHORT BytesCount,
  75. IN BOOLEAN CopyData
  76. );
  77. BOOLEAN
  78. VerifyBurstRead(
  79. PIRP_CONTEXT IrpContext
  80. );
  81. VOID
  82. FreePacketList(
  83. PIRP_CONTEXT IrpContext
  84. );
  85. NTSTATUS
  86. BurstReadReceive(
  87. IN PIRP_CONTEXT IrpContext,
  88. IN ULONG BytesAvailable,
  89. IN PULONG BytesAccepted,
  90. IN PUCHAR Response,
  91. OUT PMDL *pReceiveMdl
  92. );
  93. NTSTATUS
  94. ReadNcpReceive(
  95. IN PIRP_CONTEXT IrpContext,
  96. IN ULONG BytesAvailable,
  97. IN PULONG BytesAccepted,
  98. IN PUCHAR Response,
  99. OUT PMDL *pReceiveMdl
  100. );
  101. NTSTATUS
  102. ParseBurstReadResponse(
  103. IN PIRP_CONTEXT IrpContext,
  104. PVOID Response,
  105. ULONG BytesAvailable,
  106. PUCHAR Flags,
  107. PULONG DataOffset,
  108. PUSHORT BytesThisPacket,
  109. PUCHAR *ReadData,
  110. PULONG TotalBytesRead
  111. );
  112. PMDL
  113. AllocateReceivePartialMdl(
  114. PMDL FullMdl,
  115. ULONG DataOffset,
  116. ULONG BytesThisPacket
  117. );
  118. VOID
  119. SetConnectionTimeout(
  120. PNONPAGED_SCB pNpScb,
  121. ULONG Length
  122. );
  123. #ifdef ALLOC_PRAGMA
  124. #pragma alloc_text( PAGE, NwFsdRead )
  125. #pragma alloc_text( PAGE, NwCommonRead )
  126. #pragma alloc_text( PAGE, ReadNcp )
  127. #pragma alloc_text( PAGE, BurstRead )
  128. #pragma alloc_text( PAGE, BuildBurstReadRequest )
  129. #pragma alloc_text( PAGE, ResubmitBurstRead )
  130. #pragma alloc_text( PAGE, SetConnectionTimeout )
  131. #ifndef QFE_BUILD
  132. #pragma alloc_text( PAGE1, ReadNcpCallback )
  133. #pragma alloc_text( PAGE1, ReadNcpReceive )
  134. #pragma alloc_text( PAGE1, BuildReadNcp )
  135. #pragma alloc_text( PAGE1, ParseReadResponse )
  136. #pragma alloc_text( PAGE1, BurstReadCallback )
  137. #pragma alloc_text( PAGE1, BurstReadTimeout )
  138. #pragma alloc_text( PAGE1, RecordPacketReceipt )
  139. #pragma alloc_text( PAGE1, VerifyBurstRead )
  140. #pragma alloc_text( PAGE1, FreePacketList )
  141. #pragma alloc_text( PAGE1, BurstReadReceive )
  142. #pragma alloc_text( PAGE1, ParseBurstReadResponse )
  143. #pragma alloc_text( PAGE1, AllocateReceivePartialMdl )
  144. #endif
  145. #endif
  146. #if 0 // Not pageable
  147. // see ifndef QFE_BUILD above
  148. #endif
  149. NTSTATUS
  150. NwFsdRead(
  151. IN PDEVICE_OBJECT DeviceObject,
  152. IN PIRP Irp
  153. )
  154. /*++
  155. Routine Description:
  156. This routine is the FSD routine that handles NtReadFile.
  157. Arguments:
  158. NwfsDeviceObject - Supplies the device object for the read function.
  159. Irp - Supplies the IRP to process.
  160. Return Value:
  161. NTSTATUS - The result status.
  162. --*/
  163. {
  164. PIRP_CONTEXT pIrpContext = NULL;
  165. NTSTATUS status;
  166. BOOLEAN TopLevel;
  167. PAGED_CODE();
  168. DebugTrace(+1, Dbg, "NwFsdRead\n", 0);
  169. //
  170. // Call the common direcotry control routine.
  171. //
  172. FsRtlEnterFileSystem();
  173. TopLevel = NwIsIrpTopLevel( Irp );
  174. try {
  175. pIrpContext = AllocateIrpContext( Irp );
  176. status = NwCommonRead( pIrpContext );
  177. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  178. if ( pIrpContext == NULL ) {
  179. //
  180. // If we couldn't allocate an irp context, just complete
  181. // irp without any fanfare.
  182. //
  183. status = STATUS_INSUFFICIENT_RESOURCES;
  184. Irp->IoStatus.Status = status;
  185. Irp->IoStatus.Information = 0;
  186. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  187. } else {
  188. //
  189. // We had some trouble trying to perform the requested
  190. // operation, so we'll abort the I/O request with
  191. // the error Status that we get back from the
  192. // execption code
  193. //
  194. status = NwProcessException( pIrpContext, GetExceptionCode() );
  195. }
  196. }
  197. if ( pIrpContext ) {
  198. if ( status != STATUS_PENDING ) {
  199. NwDequeueIrpContext( pIrpContext, FALSE );
  200. }
  201. NwCompleteRequest( pIrpContext, status );
  202. }
  203. if ( TopLevel ) {
  204. NwSetTopLevelIrp( NULL );
  205. }
  206. FsRtlExitFileSystem();
  207. //
  208. // Return to the caller.
  209. //
  210. DebugTrace(-1, Dbg, "NwFsdRead -> %08lx\n", status );
  211. Stats.ReadOperations++;
  212. return status;
  213. }
  214. NTSTATUS
  215. NwCommonRead (
  216. IN PIRP_CONTEXT IrpContext
  217. )
  218. /*++
  219. Routine Description:
  220. This routine does the common code for NtReadFile.
  221. Arguments:
  222. IrpContext - Supplies the request being processed.
  223. Return Value:
  224. NTSTATUS - The return status for the operation
  225. --*/
  226. {
  227. NTSTATUS status;
  228. PIRP Irp;
  229. PIO_STACK_LOCATION irpSp;
  230. NODE_TYPE_CODE nodeTypeCode;
  231. PICB icb;
  232. PFCB fcb;
  233. PVOID fsContext;
  234. ULONG BufferLength; // Size application requested to read
  235. ULONG ByteOffset;
  236. ULONG PreviousByteOffset;
  237. ULONG BytesRead;
  238. ULONG NewBufferLength = 0;
  239. PVOID SystemBuffer;
  240. //
  241. // Get the current stack location
  242. //
  243. Irp = IrpContext->pOriginalIrp;
  244. irpSp = IoGetCurrentIrpStackLocation( Irp );
  245. DebugTrace(+1, Dbg, "CommonRead...\n", 0);
  246. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG_PTR)Irp);
  247. DebugTrace( 0, Dbg, "IrpSp = %08lx\n", (ULONG_PTR)irpSp);
  248. DebugTrace( 0, Dbg, "Irp->OriginalFileObject = %08lx\n", (ULONG_PTR)(Irp->Tail.Overlay.OriginalFileObject));
  249. //
  250. // Decode the file object to figure out who we are. If the result
  251. // is not the root DCB then its an illegal parameter.
  252. //
  253. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  254. &fsContext,
  255. (PVOID *)&icb );
  256. fcb = (PFCB)icb->SuperType.Fcb;
  257. if (((nodeTypeCode != NW_NTC_ICB) &&
  258. (nodeTypeCode != NW_NTC_ICB_SCB)) ||
  259. (!icb->HasRemoteHandle) ) {
  260. DebugTrace(0, Dbg, "Not a file\n", 0);
  261. status = STATUS_INVALID_PARAMETER;
  262. DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", status );
  263. return status;
  264. }
  265. //
  266. // Make sure that this ICB is still active.
  267. //
  268. NwVerifyIcbSpecial( icb );
  269. if ( fcb->NodeTypeCode == NW_NTC_FCB ) {
  270. IrpContext->pScb = fcb->Scb;
  271. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  272. IrpContext->Icb = icb;
  273. } else if ( fcb->NodeTypeCode == NW_NTC_SCB ) {
  274. IrpContext->pScb = icb->SuperType.Scb;
  275. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  276. IrpContext->Icb = icb;
  277. fcb = NULL;
  278. } else {
  279. DebugTrace(0, Dbg, "Not a file\n", 0);
  280. status = STATUS_INVALID_PARAMETER;
  281. DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", status );
  282. return status;
  283. }
  284. BufferLength = irpSp->Parameters.Read.Length;
  285. ByteOffset = irpSp->Parameters.Read.ByteOffset.LowPart;
  286. //
  287. // Fail reads beyond file offset 4GB.
  288. //
  289. if ( irpSp->Parameters.Read.ByteOffset.HighPart != 0 ) {
  290. return( STATUS_INVALID_PARAMETER );
  291. }
  292. //
  293. // Special case 0 length read.
  294. //
  295. if ( BufferLength == 0 ) {
  296. Irp->IoStatus.Information = 0;
  297. return( STATUS_SUCCESS );
  298. }
  299. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  300. !FlagOn( Irp->Flags, IRP_PAGING_IO)) {
  301. PreviousByteOffset = irpSp->FileObject->CurrentByteOffset.LowPart;
  302. irpSp->FileObject->CurrentByteOffset.LowPart = ByteOffset;
  303. }
  304. //
  305. // First flush the write behind cache unless this is a
  306. // file stream operation.
  307. //
  308. if ( fcb ) {
  309. status = AcquireFcbAndFlushCache( IrpContext, fcb->NonPagedFcb );
  310. if ( !NT_SUCCESS( status ) ) {
  311. goto ResetByteOffsetAndExit;
  312. }
  313. //
  314. // Read as much as we can from cache.
  315. //
  316. NwMapUserBuffer( Irp, KernelMode, &SystemBuffer );
  317. //
  318. // tommye
  319. //
  320. // NwMapUserBuffer may return a NULL SystemBuffer in low resource
  321. // situations; this was not being checked.
  322. //
  323. if (SystemBuffer == NULL) {
  324. DebugTrace(-1, Dbg, "NwMapUserBuffer returned NULL OutputBuffer", 0);
  325. status = STATUS_INSUFFICIENT_RESOURCES;
  326. goto ResetByteOffsetAndExit;
  327. }
  328. BytesRead = CacheRead(
  329. fcb->NonPagedFcb,
  330. ByteOffset,
  331. BufferLength,
  332. #if NWFASTIO
  333. SystemBuffer,
  334. FALSE );
  335. #else
  336. SystemBuffer );
  337. #endif
  338. //
  339. // If all the data was the the cache, we are done.
  340. //
  341. if ( BytesRead == BufferLength ) {
  342. Irp->IoStatus.Information = BytesRead;
  343. //
  344. // Update the current byte offset in the file if it is a
  345. // synchronous file (and this is not paging I/O).
  346. //
  347. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  348. !FlagOn( Irp->Flags, IRP_PAGING_IO)) {
  349. irpSp->FileObject->CurrentByteOffset.QuadPart += BytesRead;
  350. }
  351. //
  352. // If this is a paging read, we need to flush the MDL
  353. // since on some systems the I-cache and D-cache
  354. // are not synchronized.
  355. //
  356. if (FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  357. KeFlushIoBuffers( Irp->MdlAddress, TRUE, FALSE);
  358. }
  359. //
  360. // Record read offset and size to discover a sequential read pattern.
  361. //
  362. fcb->LastReadOffset = irpSp->Parameters.Read.ByteOffset.LowPart;
  363. fcb->LastReadSize = irpSp->Parameters.Read.Length;
  364. DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", STATUS_SUCCESS );
  365. return( STATUS_SUCCESS );
  366. }
  367. NwAppendToQueueAndWait( IrpContext );
  368. // Protect read cache
  369. NwAcquireExclusiveFcb( fcb->NonPagedFcb, TRUE );
  370. IrpContext->Specific.Read.CacheReadSize = BytesRead;
  371. fcb->NonPagedFcb->CacheFileOffset = ByteOffset + BufferLength;
  372. ByteOffset += BytesRead;
  373. BufferLength -= BytesRead;
  374. NewBufferLength = CalculateReadAheadSize(
  375. IrpContext,
  376. fcb->NonPagedFcb,
  377. BytesRead,
  378. ByteOffset,
  379. BufferLength );
  380. IrpContext->Specific.Read.ReadAheadSize = NewBufferLength - BufferLength;
  381. } else {
  382. //
  383. // This is a read from a ds file stream handle. For now,
  384. // there's no cache support.
  385. //
  386. NwAppendToQueueAndWait( IrpContext );
  387. BytesRead = 0;
  388. IrpContext->Specific.Read.CacheReadSize = BytesRead;
  389. IrpContext->Specific.Read.ReadAheadSize = 0;
  390. }
  391. //
  392. // If burst mode is enabled, and this read is too big to do in a single
  393. // core read NCP, use burst mode.
  394. //
  395. // We don't support burst against a ds file stream yet.
  396. //
  397. if ( IrpContext->pNpScb->ReceiveBurstModeEnabled &&
  398. NewBufferLength > IrpContext->pNpScb->BufferSize &&
  399. fcb ) {
  400. status = BurstRead( IrpContext );
  401. } else {
  402. status = ReadNcp( IrpContext );
  403. }
  404. Irp->MdlAddress = IrpContext->pOriginalMdlAddress;
  405. if (Irp->MdlAddress != NULL) {
  406. // Next might point to the cache mdl.
  407. Irp->MdlAddress->Next = NULL;
  408. }
  409. if ( NT_SUCCESS( status ) ) {
  410. //
  411. // Update the current byte offset in the file if it is a
  412. // synchronous file (and this is not paging I/O).
  413. //
  414. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  415. !FlagOn( Irp->Flags, IRP_PAGING_IO)) {
  416. irpSp->FileObject->CurrentByteOffset.QuadPart += Irp->IoStatus.Information;
  417. }
  418. //
  419. // If this is a paging read, we need to flush the MDL
  420. // since on some systems the I-cache and D-cache
  421. // are not synchronized.
  422. //
  423. if (FlagOn(Irp->Flags, IRP_PAGING_IO)) {
  424. KeFlushIoBuffers( Irp->MdlAddress, TRUE, FALSE);
  425. }
  426. //
  427. // If we received 0 bytes without an error, we must be beyond
  428. // the end of file.
  429. //
  430. if ( Irp->IoStatus.Information == 0 ) {
  431. status = STATUS_END_OF_FILE;
  432. }
  433. }
  434. //
  435. // Record read offset and size to discover a sequential read pattern.
  436. //
  437. if ( fcb ) {
  438. fcb->LastReadOffset = irpSp->Parameters.Read.ByteOffset.LowPart;
  439. fcb->LastReadSize = irpSp->Parameters.Read.Length;
  440. NwReleaseFcb( fcb->NonPagedFcb );
  441. }
  442. DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", status);
  443. ResetByteOffsetAndExit:
  444. //
  445. // I have seen a case where the Fileobject is nonexistant after errors.
  446. //
  447. if ( !NT_SUCCESS( status ) ) {
  448. if (!(irpSp->FileObject)) {
  449. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "Fileobject has disappeared\n", 0);
  450. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "Irp = %08lx\n", (ULONG_PTR)Irp);
  451. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "IrpSp = %08lx\n", (ULONG_PTR)irpSp);
  452. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "Irp->OriginalFileObject = %08lx\n", (ULONG_PTR)Irp->Tail.Overlay.OriginalFileObject);
  453. DbgBreakPoint();
  454. }
  455. if (FlagOn(irpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) &&
  456. !FlagOn( Irp->Flags, IRP_PAGING_IO)) {
  457. irpSp->FileObject->CurrentByteOffset.LowPart = PreviousByteOffset;
  458. }
  459. }
  460. return status;
  461. }
  462. NTSTATUS
  463. ReadNcp(
  464. PIRP_CONTEXT IrpContext
  465. )
  466. /*++
  467. Routine Description:
  468. This routine exchanges a series of read NCPs with the server.
  469. Arguments:
  470. IrpContext - A pointer to IRP context information for this request.
  471. Icb - Supplies the file specific information.
  472. Return Value:
  473. Status of transfer.
  474. --*/
  475. {
  476. PIRP irp;
  477. PIO_STACK_LOCATION irpSp;
  478. ULONG Length; // Size we will send to the server
  479. PMDL DataMdl;
  480. PSCB pScb;
  481. PNONPAGED_SCB pNpScb;
  482. NTSTATUS status = STATUS_UNSUCCESSFUL;
  483. PICB Icb;
  484. ULONG ByteOffset;
  485. ULONG BufferLength;
  486. ULONG MdlLength;
  487. BOOLEAN Done;
  488. PMDL Mdl, NextMdl;
  489. irp = IrpContext->pOriginalIrp;
  490. irpSp = IoGetCurrentIrpStackLocation( irp );
  491. Icb = IrpContext->Icb;
  492. BufferLength = irpSp->Parameters.Read.Length +
  493. IrpContext->Specific.Read.ReadAheadSize -
  494. IrpContext->Specific.Read.CacheReadSize;
  495. ByteOffset = irpSp->Parameters.Read.ByteOffset.LowPart +
  496. IrpContext->Specific.Read.CacheReadSize;
  497. IrpContext->Specific.Read.FileOffset = ByteOffset;
  498. DebugTrace(+1, Dbg, "ReadNcp...\n", 0);
  499. DebugTrace( 0, Dbg, "irp = %08lx\n", (ULONG_PTR)irp);
  500. DebugTrace( 0, Dbg, "File = %wZ\n", &Icb->SuperType.Fcb->FullFileName);
  501. DebugTrace( 0, Dbg, "Length = %ld\n", BufferLength);
  502. DebugTrace( 0, Dbg, "Offset = %d\n", ByteOffset);
  503. if ( Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_FCB ) {
  504. pScb = Icb->SuperType.Fcb->Scb;
  505. } else if ( Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_SCB ) {
  506. pScb = Icb->SuperType.Scb;
  507. }
  508. ASSERT( pScb );
  509. //
  510. // Update the original MDL record in the Irp context so that we
  511. // can restore it on i/o completion.
  512. //
  513. IrpContext->pOriginalMdlAddress = irp->MdlAddress;
  514. Length = MIN( IrpContext->pNpScb->BufferSize, BufferLength );
  515. //
  516. // The old servers will not accept reads that cross 4k boundaries in the file
  517. //
  518. if ((IrpContext->pNpScb->PageAlign) &&
  519. (DIFFERENT_PAGES( ByteOffset, Length ))) {
  520. Length = 4096 - ((ULONG)ByteOffset & (4096-1));
  521. }
  522. IrpContext->Specific.Read.Buffer = irp->UserBuffer;
  523. IrpContext->Specific.Read.ReadOffset = IrpContext->Specific.Read.CacheReadSize;
  524. IrpContext->Specific.Read.RemainingLength = BufferLength;
  525. IrpContext->Specific.Read.PartialMdl = NULL;
  526. //
  527. // Set up to process a read NCP
  528. //
  529. pNpScb = pScb->pNpScb;
  530. IrpContext->pEx = ReadNcpCallback;
  531. IrpContext->Destination = pNpScb->RemoteAddress;
  532. IrpContext->PacketType = NCP_FUNCTION;
  533. IrpContext->ReceiveDataRoutine = ReadNcpReceive;
  534. pNpScb->MaxTimeOut = 2 * pNpScb->TickCount + 10;
  535. pNpScb->TimeOut = pNpScb->SendTimeout;
  536. pNpScb->RetryCount = DefaultRetryCount;
  537. Done = FALSE;
  538. while ( !Done ) {
  539. //
  540. // Setup to do at most 64K of i/o asynchronously, or buffer length.
  541. //
  542. IrpContext->Specific.Read.BurstSize =
  543. MIN( 64 * 1024, IrpContext->Specific.Read.RemainingLength );
  544. IrpContext->Specific.Read.BurstRequestOffset = 0;
  545. //
  546. // Try to allocate an MDL for this i/o.
  547. //
  548. if ( IrpContext->Specific.Read.ReadAheadSize == 0 ) {
  549. MdlLength = IrpContext->Specific.Read.BurstSize;
  550. } else {
  551. MdlLength = IrpContext->Specific.Read.BurstSize - IrpContext->Specific.Read.ReadAheadSize;
  552. }
  553. DataMdl = ALLOCATE_MDL(
  554. (PCHAR)IrpContext->Specific.Read.Buffer +
  555. IrpContext->Specific.Read.ReadOffset,
  556. MdlLength,
  557. FALSE, // Secondary Buffer
  558. FALSE, // Charge Quota
  559. NULL);
  560. if ( DataMdl == NULL ) {
  561. return STATUS_INSUFFICIENT_RESOURCES;
  562. }
  563. IrpContext->Specific.Read.FullMdl = DataMdl;
  564. //
  565. // If there is no MDL for this read, probe the data MDL to
  566. // lock it's pages down. Otherwise, use the data MDL as
  567. // a partial MDL.
  568. //
  569. if ( IrpContext->pOriginalMdlAddress == NULL ) {
  570. try {
  571. MmProbeAndLockPages( DataMdl, irp->RequestorMode, IoWriteAccess);
  572. } except (EXCEPTION_EXECUTE_HANDLER) {
  573. FREE_MDL( DataMdl );
  574. return GetExceptionCode();
  575. }
  576. } else {
  577. IoBuildPartialMdl(
  578. IrpContext->pOriginalMdlAddress,
  579. DataMdl,
  580. (PCHAR)IrpContext->Specific.Read.Buffer +
  581. IrpContext->Specific.Read.ReadOffset,
  582. MdlLength );
  583. }
  584. IrpContext->Specific.Read.BurstBuffer = MmGetSystemAddressForMdlSafe( DataMdl, NormalPagePriority );
  585. if (IrpContext->Specific.Read.BurstBuffer == NULL) {
  586. if ( IrpContext->pOriginalMdlAddress == NULL ) {
  587. //
  588. // Unlock the pages which we just locked.
  589. //
  590. MmUnlockPages( DataMdl );
  591. }
  592. IrpContext->Specific.Read.FullMdl = NULL;
  593. FREE_MDL( DataMdl );
  594. return STATUS_NO_MEMORY;
  595. }
  596. if ( IrpContext->Specific.Read.BurstSize ==
  597. IrpContext->Specific.Read.RemainingLength ) {
  598. Done = TRUE;
  599. }
  600. if ( IrpContext->Specific.Read.ReadAheadSize != 0 ) {
  601. DataMdl->Next = Icb->NpFcb->CacheMdl;
  602. }
  603. IrpContext->Specific.Read.LastReadLength = Length;
  604. //
  605. // Build and send the request.
  606. //
  607. BuildReadNcp(
  608. IrpContext,
  609. IrpContext->Specific.Read.FileOffset,
  610. (USHORT) MIN( Length, IrpContext->Specific.Read.RemainingLength ) );
  611. status = PrepareAndSendPacket( IrpContext );
  612. if ( NT_SUCCESS( status )) {
  613. KeWaitForSingleObject(
  614. &IrpContext->Event,
  615. Executive,
  616. KernelMode,
  617. FALSE,
  618. NULL
  619. );
  620. status = IrpContext->Specific.Read.Status;
  621. }
  622. //
  623. // Stop looping if the read failed, or we read less data than
  624. // requested.
  625. //
  626. if ( !NT_SUCCESS( status ) ||
  627. IrpContext->Specific.Read.BurstSize != 0 ) {
  628. Done = TRUE;
  629. }
  630. if ( IrpContext->pOriginalMdlAddress == NULL ) {
  631. MmUnlockPages( DataMdl );
  632. }
  633. FREE_MDL( DataMdl );
  634. }
  635. //
  636. // Free the receive MDL if one was allocated.
  637. //
  638. Mdl = IrpContext->Specific.Read.PartialMdl;
  639. while ( Mdl != NULL ) {
  640. NextMdl = Mdl->Next;
  641. FREE_MDL( Mdl );
  642. Mdl = NextMdl;
  643. }
  644. DebugTrace(-1, Dbg, "ReadNcp -> %08lx\n", status );
  645. Stats.ReadNcps++;
  646. return status;
  647. }
  648. NTSTATUS
  649. ReadNcpCallback (
  650. IN PIRP_CONTEXT IrpContext,
  651. IN ULONG BytesAvailable,
  652. IN PUCHAR Response
  653. )
  654. /*++
  655. Routine Description:
  656. This routine receives the response from a user NCP.
  657. Arguments:
  658. IrpContext - A pointer to IRP context information for this request.
  659. BytesAvailable - Number of bytes in the response.
  660. Response - The response data.
  661. Return Value:
  662. VOID
  663. --*/
  664. {
  665. NTSTATUS Status = STATUS_SUCCESS;
  666. PIRP Irp;
  667. PIO_STACK_LOCATION irpSp;
  668. ULONG Length;
  669. USHORT USLength;
  670. PNONPAGED_FCB NpFcb;
  671. DebugTrace(0, Dbg, "ReadNcpCallback...\n", 0);
  672. if ( BytesAvailable == 0) {
  673. //
  674. // No response from server. Status is in pIrpContext->
  675. // ResponseParameters.Error
  676. //
  677. IrpContext->Specific.Read.Status = STATUS_REMOTE_NOT_LISTENING;
  678. NwSetIrpContextEvent( IrpContext );
  679. return STATUS_REMOTE_NOT_LISTENING;
  680. }
  681. //
  682. // How much data was received?
  683. //
  684. Status = ParseReadResponse(
  685. IrpContext,
  686. (PNCP_READ_RESPONSE)Response,
  687. BytesAvailable,
  688. &USLength );
  689. Length = (ULONG)USLength;
  690. DebugTrace(0, Dbg, "Ncp contains %d bytes\n", Length);
  691. if ((NT_SUCCESS(Status)) &&
  692. (Length != 0)) {
  693. //
  694. // If we are receiving the data at indication time, copy the
  695. // user's data to the user's buffer.
  696. //
  697. if ( Response != IrpContext->rsp ) {
  698. //
  699. // Read in the data.
  700. // Note: If the FileOffset is at an odd byte then the server
  701. // will insert an extra pad byte.
  702. //
  703. CopyBufferToMdl(
  704. IrpContext->Specific.Read.FullMdl,
  705. IrpContext->Specific.Read.BurstRequestOffset,
  706. Response + sizeof( NCP_READ_RESPONSE ) + ( IrpContext->Specific.Read.FileOffset & 1),
  707. Length );
  708. DebugTrace( 0, Dbg, "RxLength= %ld\n", Length);
  709. dump( Dbg,(PUCHAR)IrpContext->Specific.Read.BurstBuffer +
  710. IrpContext->Specific.Read.BurstRequestOffset,
  711. Length);
  712. }
  713. DebugTrace( 0, Dbg, "RxLength= %ld\n", Length);
  714. IrpContext->Specific.Read.ReadOffset += Length;
  715. IrpContext->Specific.Read.BurstRequestOffset += Length;
  716. IrpContext->Specific.Read.FileOffset += Length;
  717. IrpContext->Specific.Read.RemainingLength -= Length;
  718. IrpContext->Specific.Read.BurstSize -= Length;
  719. }
  720. DebugTrace( 0, Dbg, "RemainingLength = %ld\n",IrpContext->Specific.Read.RemainingLength);
  721. //
  722. // If the previous read was succesful, and we received as much data
  723. // as we asked for, and there is more locked data, send the next
  724. // read request.
  725. //
  726. if ( ( NT_SUCCESS( Status ) ) &&
  727. ( IrpContext->Specific.Read.BurstSize != 0 ) &&
  728. ( Length == IrpContext->Specific.Read.LastReadLength ) ) {
  729. //
  730. // Read the next packet.
  731. //
  732. Length = MIN( IrpContext->pNpScb->BufferSize,
  733. IrpContext->Specific.Read.BurstSize );
  734. //
  735. // The server will not accept reads that cross 4k boundaries
  736. // in the file.
  737. //
  738. if ((IrpContext->pNpScb->PageAlign) &&
  739. (DIFFERENT_PAGES( IrpContext->Specific.Read.FileOffset, Length ))) {
  740. Length = 4096 - ((ULONG)IrpContext->Specific.Read.FileOffset & (4096-1));
  741. }
  742. IrpContext->Specific.Read.LastReadLength = Length;
  743. DebugTrace( 0, Dbg, "Length = %ld\n", Length);
  744. //
  745. // Build and send the request.
  746. //
  747. BuildReadNcp(
  748. IrpContext,
  749. IrpContext->Specific.Read.FileOffset,
  750. (USHORT)Length );
  751. Status = PrepareAndSendPacket( IrpContext );
  752. Stats.ReadNcps++;
  753. if ( !NT_SUCCESS(Status) ) {
  754. // Abandon this request
  755. goto returnstatus;
  756. }
  757. } else {
  758. returnstatus:
  759. Irp = IrpContext->pOriginalIrp;
  760. irpSp = IoGetCurrentIrpStackLocation( Irp );
  761. NpFcb = IrpContext->Icb->NpFcb;
  762. if ( IrpContext->Icb->NodeTypeCode == NW_NTC_ICB_SCB ) {
  763. NpFcb = NULL;
  764. }
  765. //
  766. // Calculate how much data we read into the cache, and how much data
  767. // we read into the users buffer.
  768. //
  769. if ( NpFcb ) {
  770. if ( IrpContext->Specific.Read.ReadOffset > irpSp->Parameters.Read.Length ) {
  771. ASSERT(NpFcb->CacheBuffer != NULL ) ; // had better be there..
  772. NpFcb->CacheDataSize = IrpContext->Specific.Read.ReadOffset -
  773. irpSp->Parameters.Read.Length;
  774. Irp->IoStatus.Information = irpSp->Parameters.Read.Length;
  775. } else {
  776. NpFcb->CacheDataSize = 0;
  777. Irp->IoStatus.Information = IrpContext->Specific.Read.ReadOffset;
  778. }
  779. } else {
  780. Irp->IoStatus.Information = IrpContext->Specific.Read.ReadOffset;
  781. }
  782. //
  783. // We're done with this request, signal the reading thread.
  784. //
  785. IrpContext->Specific.Read.Status = Status;
  786. NwSetIrpContextEvent( IrpContext );
  787. }
  788. DebugTrace( 0, Dbg, "ReadNcpCallback -> %08lx\n", Status );
  789. return STATUS_SUCCESS;
  790. }
  791. NTSTATUS
  792. ReadNcpReceive(
  793. IN PIRP_CONTEXT IrpContext,
  794. IN ULONG BytesAvailable,
  795. IN PULONG BytesAccepted,
  796. IN PUCHAR Response,
  797. OUT PMDL *pReceiveMdl
  798. )
  799. {
  800. PMDL ReceiveMdl;
  801. PMDL Mdl, NextMdl;
  802. DebugTrace( 0, Dbg, "ReadNcpReceive\n", 0 );
  803. Mdl = IrpContext->Specific.Read.PartialMdl;
  804. IrpContext->Specific.Read.PartialMdl = NULL;
  805. while ( Mdl != NULL ) {
  806. NextMdl = Mdl->Next;
  807. FREE_MDL( Mdl );
  808. Mdl = NextMdl;
  809. }
  810. //
  811. // Set up receive MDL. Note that we get an extra byte of header
  812. // when reading from an odd offset.
  813. //
  814. IrpContext->RxMdl->ByteCount = sizeof( NCP_READ_RESPONSE ) +
  815. (IrpContext->Specific.Read.FileOffset & 1);
  816. ASSERT( IrpContext->Specific.Read.FullMdl != NULL );
  817. //
  818. // If we are reading at EOF, or there was a read error there will
  819. // be a small response.
  820. //
  821. if ( BytesAvailable > MmGetMdlByteCount( IrpContext->RxMdl ) ) {
  822. ReceiveMdl = AllocateReceivePartialMdl(
  823. IrpContext->Specific.Read.FullMdl,
  824. IrpContext->Specific.Read.BurstRequestOffset,
  825. BytesAvailable - MmGetMdlByteCount( IrpContext->RxMdl ) );
  826. IrpContext->RxMdl->Next = ReceiveMdl;
  827. // Record Mdl to free when CopyIndicatedData or Irp completed.
  828. IrpContext->Specific.Read.PartialMdl = ReceiveMdl;
  829. } else {
  830. IrpContext->RxMdl->Next = NULL;
  831. }
  832. *pReceiveMdl = IrpContext->RxMdl;
  833. return STATUS_SUCCESS;
  834. }
  835. VOID
  836. BuildReadNcp(
  837. PIRP_CONTEXT IrpContext,
  838. ULONG FileOffset,
  839. USHORT Length
  840. )
  841. {
  842. PNCP_READ_REQUEST ReadRequest;
  843. ReadRequest = (PNCP_READ_REQUEST)IrpContext->req;
  844. ReadRequest->RequestHeader.NcpHeader.Command = PEP_COMMAND_REQUEST;
  845. ReadRequest->RequestHeader.NcpHeader.ConnectionIdLow =
  846. IrpContext->pNpScb->ConnectionNo;
  847. ReadRequest->RequestHeader.NcpHeader.ConnectionIdHigh =
  848. IrpContext->pNpScb->ConnectionNoHigh;
  849. ReadRequest->RequestHeader.NcpHeader.TaskId =
  850. IrpContext->Icb->Pid;
  851. ReadRequest->RequestHeader.FunctionCode = NCP_READ_FILE;
  852. ReadRequest->Unused = 0;
  853. RtlMoveMemory(
  854. ReadRequest->Handle,
  855. IrpContext->Icb->Handle,
  856. sizeof( IrpContext->Icb->Handle ) );
  857. LongByteSwap( ReadRequest->FileOffset, FileOffset );
  858. ShortByteSwap( ReadRequest->Length, Length );
  859. IrpContext->TxMdl->ByteCount = sizeof( *ReadRequest );
  860. SetFlag( IrpContext->Flags, IRP_FLAG_SEQUENCE_NO_REQUIRED );
  861. ClearFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  862. return;
  863. }
  864. NTSTATUS
  865. ParseReadResponse(
  866. PIRP_CONTEXT IrpContext,
  867. PNCP_READ_RESPONSE Response,
  868. ULONG BytesAvailable,
  869. PUSHORT Length )
  870. {
  871. NTSTATUS Status;
  872. Status = ParseNcpResponse( IrpContext, &Response->ResponseHeader );
  873. if (!NT_SUCCESS(Status)) {
  874. return( Status );
  875. }
  876. if ( BytesAvailable < sizeof( NCP_READ_RESPONSE ) ) {
  877. return( STATUS_UNEXPECTED_NETWORK_ERROR );
  878. }
  879. ShortByteSwap( *Length, Response->Length );
  880. return( Status );
  881. }
  882. NTSTATUS
  883. BurstRead(
  884. PIRP_CONTEXT IrpContext
  885. )
  886. /*++
  887. Routine Description:
  888. This routine exchanges a series of burst read NCPs with the server.
  889. Arguments:
  890. IrpContext - A pointer to IRP context information for this request.
  891. ByteOffset - The file offset for the read.
  892. BufferLength - The number of bytes to read.
  893. Return Value:
  894. Status of transfer.
  895. --*/
  896. {
  897. PIRP irp;
  898. PIO_STACK_LOCATION irpSp;
  899. ULONG Length; // Size we will send to the server
  900. PMDL DataMdl;
  901. ULONG MdlLength;
  902. PSCB pScb;
  903. NTSTATUS status = STATUS_UNSUCCESSFUL;
  904. PICB Icb;
  905. PNONPAGED_SCB pNpScb;
  906. ULONG ByteOffset;
  907. ULONG BufferLength;
  908. BOOLEAN Done;
  909. PAGED_CODE();
  910. pNpScb = IrpContext->pNpScb;
  911. irp = IrpContext->pOriginalIrp;
  912. irpSp = IoGetCurrentIrpStackLocation( irp );
  913. Icb = IrpContext->Icb;
  914. BufferLength = irpSp->Parameters.Read.Length +
  915. IrpContext->Specific.Read.ReadAheadSize -
  916. IrpContext->Specific.Read.CacheReadSize;
  917. ByteOffset = irpSp->Parameters.Read.ByteOffset.LowPart +
  918. IrpContext->Specific.Read.CacheReadSize;
  919. IrpContext->Specific.Read.FileOffset = ByteOffset;
  920. IrpContext->Specific.Read.TotalReadOffset = ByteOffset;
  921. IrpContext->Specific.Read.TotalReadLength = BufferLength;
  922. DebugTrace(+1, Dbg, "BurstRead...\n", 0);
  923. DebugTrace( 0, Dbg, "irp = %08lx\n", (ULONG_PTR)irp);
  924. DebugTrace( 0, Dbg, "File = %wZ\n", &Icb->SuperType.Fcb->FullFileName);
  925. DebugTrace( 0, Dbg, "Length = %ld\n", BufferLength);
  926. DebugTrace( 0, Dbg, "Offset = %ld\n", ByteOffset);
  927. DebugTrace( 0, Dbg, "Org Len = %ld\n", irpSp->Parameters.Read.Length );
  928. DebugTrace( 0, Dbg, "Org Off = %ld\n", irpSp->Parameters.Read.ByteOffset.LowPart );
  929. ASSERT (Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_FCB);
  930. pScb = Icb->SuperType.Fcb->Scb;
  931. ASSERT (pScb->NodeTypeCode == NW_NTC_SCB);
  932. //
  933. // Update the original MDL record in the Irp context so that we
  934. // can restore it on i/o completion.
  935. //
  936. IrpContext->pOriginalMdlAddress = irp->MdlAddress;
  937. Length = MIN( pNpScb->MaxReceiveSize, BufferLength );
  938. if ( pNpScb->BurstRenegotiateReqd ) {
  939. pNpScb->BurstRenegotiateReqd = FALSE;
  940. RenegotiateBurstMode( IrpContext, pNpScb );
  941. }
  942. IrpContext->Specific.Read.ReadOffset = IrpContext->Specific.Read.CacheReadSize;
  943. IrpContext->Specific.Read.RemainingLength = BufferLength;
  944. IrpContext->Specific.Read.LastReadLength = Length;
  945. InitializeListHead( &IrpContext->Specific.Read.PacketList );
  946. IrpContext->Specific.Read.BurstRequestOffset = 0;
  947. IrpContext->Specific.Read.BurstSize = 0;
  948. IrpContext->Specific.Read.DataReceived = FALSE;
  949. IrpContext->pTdiStruct = &pNpScb->Burst;
  950. IrpContext->TimeoutRoutine = BurstReadTimeout;
  951. IrpContext->ReceiveDataRoutine = BurstReadReceive;
  952. IrpContext->Specific.Read.Buffer = irp->UserBuffer;
  953. IrpContext->pEx = BurstReadCallback;
  954. IrpContext->Destination = pNpScb->RemoteAddress;
  955. IrpContext->PacketType = NCP_BURST;
  956. //
  957. // Tell BurstWrite that it needs to send a dummy Ncp on the next write.
  958. //
  959. pNpScb->BurstDataWritten = 0x00010000;
  960. //
  961. // The server will pause NwReceiveDelay between packets. Make sure we have our timeout
  962. // so that we will take that into account.
  963. //
  964. SetConnectionTimeout( IrpContext->pNpScb, Length );
  965. Done = FALSE;
  966. while ( !Done ) {
  967. //
  968. // Set burst read timeouts to how long we think the burst should take.
  969. //
  970. // tommye - MS bug 2743 changed the RetryCount from 20 to be based off the
  971. // default retry count, nudged up a little.
  972. //
  973. pNpScb->RetryCount = DefaultRetryCount * 2;
  974. //
  975. // Allocate and build an MDL for the users buffer.
  976. //
  977. if ( IrpContext->Specific.Read.ReadAheadSize == 0 ) {
  978. MdlLength = Length;
  979. } else {
  980. MdlLength = Length - IrpContext->Specific.Read.ReadAheadSize;
  981. }
  982. DataMdl = ALLOCATE_MDL(
  983. (PCHAR)IrpContext->Specific.Read.Buffer +
  984. IrpContext->Specific.Read.ReadOffset,
  985. MdlLength,
  986. FALSE, // Secondary Buffer
  987. FALSE, // Charge Quota
  988. NULL);
  989. if ( DataMdl == NULL ) {
  990. return STATUS_INSUFFICIENT_RESOURCES;
  991. }
  992. //
  993. // If there is no MDL for this read, probe the data MDL to lock it's
  994. // pages down.
  995. //
  996. // Otherwise, use the data MDL as a partial MDL and lock the pages
  997. // accordingly.
  998. //
  999. if ( IrpContext->pOriginalMdlAddress == NULL ) {
  1000. try {
  1001. MmProbeAndLockPages( DataMdl, irp->RequestorMode, IoWriteAccess);
  1002. } except (EXCEPTION_EXECUTE_HANDLER) {
  1003. FREE_MDL( DataMdl );
  1004. return GetExceptionCode();
  1005. }
  1006. } else {
  1007. IoBuildPartialMdl(
  1008. IrpContext->pOriginalMdlAddress,
  1009. DataMdl,
  1010. (PCHAR)IrpContext->Specific.Read.Buffer +
  1011. IrpContext->Specific.Read.ReadOffset,
  1012. MdlLength );
  1013. }
  1014. IrpContext->Specific.Read.BurstBuffer = MmGetSystemAddressForMdlSafe( DataMdl, NormalPagePriority );
  1015. if (IrpContext->Specific.Read.BurstBuffer == NULL) {
  1016. if ( IrpContext->pOriginalMdlAddress == NULL ) {
  1017. //
  1018. // Unlock the pages which we just locked.
  1019. //
  1020. MmUnlockPages( DataMdl );
  1021. }
  1022. FREE_MDL( DataMdl );
  1023. return STATUS_NO_MEMORY;
  1024. }
  1025. IrpContext->Specific.Read.FullMdl = DataMdl;
  1026. if ( IrpContext->Specific.Read.ReadAheadSize != 0 ) {
  1027. DataMdl->Next = Icb->NpFcb->CacheMdl;
  1028. }
  1029. SetFlag( IrpContext->Flags, IRP_FLAG_BURST_REQUEST | IRP_FLAG_BURST_PACKET );
  1030. //
  1031. // Send the request.
  1032. //
  1033. BuildBurstReadRequest(
  1034. IrpContext,
  1035. *(ULONG UNALIGNED *)(&Icb->Handle[2]),
  1036. IrpContext->Specific.Read.FileOffset,
  1037. Length );
  1038. status = PrepareAndSendPacket( IrpContext );
  1039. if ( NT_SUCCESS( status )) {
  1040. status = KeWaitForSingleObject(
  1041. &IrpContext->Event,
  1042. Executive,
  1043. KernelMode,
  1044. FALSE,
  1045. NULL
  1046. );
  1047. }
  1048. if ( IrpContext->pOriginalMdlAddress == NULL ) {
  1049. MmUnlockPages( DataMdl );
  1050. }
  1051. FREE_MDL( DataMdl );
  1052. FreePacketList( IrpContext );
  1053. ClearFlag( IrpContext->Flags, IRP_FLAG_BURST_REQUEST );
  1054. status = IrpContext->Specific.Read.Status;
  1055. if ( status != STATUS_REMOTE_NOT_LISTENING ) {
  1056. IrpContext->pNpScb->BurstRequestNo++;
  1057. NwProcessReceiveBurstSuccess( IrpContext->pNpScb );
  1058. }
  1059. if ( !NT_SUCCESS( status ) ) {
  1060. return( status );
  1061. }
  1062. //
  1063. // Update the read status data.
  1064. //
  1065. IrpContext->Specific.Read.ReadOffset +=
  1066. IrpContext->Specific.Read.BurstSize;
  1067. IrpContext->Specific.Read.FileOffset +=
  1068. IrpContext->Specific.Read.BurstSize;
  1069. IrpContext->Specific.Read.RemainingLength -=
  1070. IrpContext->Specific.Read.BurstSize;
  1071. if ( IrpContext->Specific.Read.LastReadLength ==
  1072. IrpContext->Specific.Read.BurstSize &&
  1073. IrpContext->Specific.Read.RemainingLength > 0 ) {
  1074. //
  1075. // We've received all the data from the current burst, and we
  1076. // received as many bytes as we asked for, and we need more data
  1077. // to satisfy the users read request, start another read burst.
  1078. //
  1079. Length = MIN( IrpContext->pNpScb->MaxReceiveSize,
  1080. IrpContext->Specific.Read.RemainingLength );
  1081. DebugTrace( 0, Dbg, "Requesting another burst, length = %ld\n", Length);
  1082. ASSERT( Length != 0 );
  1083. IrpContext->Specific.Read.LastReadLength = Length;
  1084. (PUCHAR)IrpContext->Specific.Read.BurstBuffer +=
  1085. IrpContext->Specific.Read.BurstSize;
  1086. IrpContext->Specific.Read.BurstRequestOffset = 0;
  1087. IrpContext->Specific.Read.BurstSize = 0;
  1088. IrpContext->Specific.Read.DataReceived = FALSE;
  1089. } else {
  1090. Done = TRUE;
  1091. }
  1092. }
  1093. //
  1094. // Calculate how much data we read into the cache, and how much data
  1095. // we read into the users buffer.
  1096. //
  1097. if ( IrpContext->Specific.Read.ReadOffset > irpSp->Parameters.Read.Length ) {
  1098. ASSERT(Icb->NpFcb->CacheBuffer != NULL ) ; // this had better be there
  1099. Icb->NpFcb->CacheDataSize =
  1100. IrpContext->Specific.Read.ReadOffset -
  1101. irpSp->Parameters.Read.Length;
  1102. irp->IoStatus.Information = irpSp->Parameters.Read.Length;
  1103. } else {
  1104. Icb->NpFcb->CacheDataSize = 0;
  1105. irp->IoStatus.Information = IrpContext->Specific.Read.ReadOffset;
  1106. }
  1107. DebugTrace( 0, Dbg, "BytesRead -> %08lx\n", irp->IoStatus.Information );
  1108. DebugTrace(-1, Dbg, "BurstRead -> %08lx\n", status );
  1109. Stats.PacketBurstReadNcps++;
  1110. return status;
  1111. }
  1112. VOID
  1113. BuildBurstReadRequest(
  1114. IN PIRP_CONTEXT IrpContext,
  1115. IN ULONG Handle,
  1116. IN ULONG FileOffset,
  1117. IN ULONG Length
  1118. )
  1119. {
  1120. PNCP_BURST_READ_REQUEST BurstRead;
  1121. PNONPAGED_SCB pNpScb;
  1122. ULONG Temp;
  1123. BurstRead = (PNCP_BURST_READ_REQUEST)(IrpContext->req);
  1124. pNpScb = IrpContext->pNpScb;
  1125. BurstRead->BurstHeader.Command = PEP_COMMAND_BURST;
  1126. BurstRead->BurstHeader.Flags = BURST_FLAG_END_OF_BURST;
  1127. BurstRead->BurstHeader.StreamType = 0x02;
  1128. BurstRead->BurstHeader.SourceConnection = pNpScb->SourceConnectionId;
  1129. BurstRead->BurstHeader.DestinationConnection = pNpScb->DestinationConnectionId;
  1130. LongByteSwap( BurstRead->BurstHeader.SendDelayTime, pNpScb->NwReceiveDelay );
  1131. pNpScb->CurrentBurstDelay = pNpScb->NwReceiveDelay;
  1132. Temp = sizeof( NCP_BURST_READ_REQUEST ) - sizeof( NCP_BURST_HEADER );
  1133. LongByteSwap( BurstRead->BurstHeader.DataSize, Temp);
  1134. BurstRead->BurstHeader.BurstOffset = 0;
  1135. ShortByteSwap( BurstRead->BurstHeader.BurstLength, Temp );
  1136. BurstRead->BurstHeader.MissingFragmentCount = 0;
  1137. BurstRead->Function = 1;
  1138. BurstRead->Handle = Handle;
  1139. LongByteSwap(
  1140. BurstRead->TotalReadOffset,
  1141. IrpContext->Specific.Read.TotalReadOffset );
  1142. LongByteSwap(
  1143. BurstRead->TotalReadLength,
  1144. IrpContext->Specific.Read.TotalReadLength );
  1145. LongByteSwap( BurstRead->Offset, FileOffset );
  1146. LongByteSwap( BurstRead->Length, Length );
  1147. IrpContext->TxMdl->ByteCount = sizeof( NCP_BURST_READ_REQUEST );
  1148. }
  1149. #ifdef NWDBG
  1150. int DropReadPackets;
  1151. #endif
  1152. NTSTATUS
  1153. BurstReadCallback (
  1154. IN PIRP_CONTEXT IrpContext,
  1155. IN ULONG BytesAvailable,
  1156. IN PUCHAR Response
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. This routine receives the response from a user NCP.
  1161. Arguments:
  1162. pIrpContext - A pointer to the context information for this IRP.
  1163. BytesAvailable - Actual number of bytes in the received message.
  1164. RspData - Points to the receive buffer.
  1165. Return Value:
  1166. The status of the operation.
  1167. --*/
  1168. {
  1169. NTSTATUS Status = STATUS_SUCCESS;
  1170. ULONG DataOffset;
  1171. ULONG TotalBytesRead;
  1172. PUCHAR ReadData;
  1173. USHORT BytesThisPacket = 0;
  1174. UCHAR Flags;
  1175. KIRQL OldIrql;
  1176. DebugTrace(+1, Dbg, "BurstReadCallback...\n", 0);
  1177. DebugTrace( 0, Dbg, "IrpContext = %X\n", IrpContext );
  1178. if ( BytesAvailable == 0) {
  1179. //
  1180. // No response from server.
  1181. //
  1182. IrpContext->Specific.Read.Status = STATUS_REMOTE_NOT_LISTENING;
  1183. NwSetIrpContextEvent( IrpContext );
  1184. DebugTrace( -1, Dbg, "BurstReadCallback -> %X\n", STATUS_REMOTE_NOT_LISTENING );
  1185. return STATUS_REMOTE_NOT_LISTENING;
  1186. }
  1187. Stats.PacketBurstReadNcps++;
  1188. if ( Response != IrpContext->rsp ) {
  1189. //
  1190. // Acquire the SCB spin lock to protect access to the list
  1191. // of received data for this read.
  1192. //
  1193. KeAcquireSpinLock( &IrpContext->pNpScb->NpScbSpinLock, &OldIrql );
  1194. Status = ParseBurstReadResponse(
  1195. IrpContext,
  1196. Response,
  1197. BytesAvailable,
  1198. &Flags,
  1199. &DataOffset,
  1200. &BytesThisPacket,
  1201. &ReadData,
  1202. &TotalBytesRead );
  1203. if ( !NT_SUCCESS( Status ) ) {
  1204. IrpContext->Specific.Read.Status = Status;
  1205. KeReleaseSpinLock( &IrpContext->pNpScb->NpScbSpinLock, OldIrql );
  1206. return( STATUS_SUCCESS );
  1207. }
  1208. //
  1209. // Update the list of data received, and copy the data to the users
  1210. // buffer.
  1211. //
  1212. RecordPacketReceipt( IrpContext, ReadData, DataOffset, BytesThisPacket, TRUE );
  1213. KeReleaseSpinLock( &IrpContext->pNpScb->NpScbSpinLock, OldIrql );
  1214. } else {
  1215. Flags = IrpContext->Specific.Read.Flags;
  1216. }
  1217. //
  1218. // If this isn't the last packet setup for the next burst packet.
  1219. //
  1220. if ( !FlagOn( Flags, BURST_FLAG_END_OF_BURST ) ) {
  1221. DebugTrace(0, Dbg, "Waiting for another packet\n", 0);
  1222. IrpContext->pNpScb->OkToReceive = TRUE;
  1223. DebugTrace( -1, Dbg, "BurstReadCallback -> %X\n", STATUS_SUCCESS );
  1224. return( STATUS_SUCCESS );
  1225. }
  1226. DebugTrace(0, Dbg, "Received final packet\n", 0);
  1227. //
  1228. // Have we received all of the data? If not, VerifyBurstRead will
  1229. // send a missing data request.
  1230. //
  1231. if ( VerifyBurstRead( IrpContext ) ) {
  1232. //
  1233. // All the data for the current burst has been received, notify
  1234. // the thread that is sending the data.
  1235. //
  1236. if (NT_SUCCESS(IrpContext->Specific.Read.Status)) {
  1237. //
  1238. // If Irp allocation fails then it is possible for the
  1239. // packet to have been recorded but not copied into the
  1240. // user buffer. In this case leave the failure status.
  1241. //
  1242. IrpContext->Specific.Read.Status = STATUS_SUCCESS;
  1243. }
  1244. NwSetIrpContextEvent( IrpContext );
  1245. }
  1246. DebugTrace( -1, Dbg, "BurstReadCallback -> %X\n", STATUS_SUCCESS );
  1247. return STATUS_SUCCESS;
  1248. }
  1249. VOID
  1250. BurstReadTimeout(
  1251. PIRP_CONTEXT IrpContext
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. This routine handles a burst read timeout, i.e. no immediate response
  1256. to the current burst read request. It request to read the packet burst
  1257. data from the last valid received packet.
  1258. Arguments:
  1259. IrpContext - A pointer to IRP context information for this request.
  1260. Return Value:
  1261. Status of transfer.
  1262. --*/
  1263. {
  1264. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1265. DebugTrace(0, Dbg, "BurstReadTimeout\n", 0 );
  1266. //
  1267. // Re-request the data we haven't received.
  1268. //
  1269. if ( !IrpContext->Specific.Read.DataReceived ) {
  1270. DebugTrace( 0, Dbg, "No packets received, retranmit\n", 0 );
  1271. SetFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1272. //
  1273. // We never received any data. Try retransmitting the previous
  1274. // request.
  1275. //
  1276. PreparePacket( IrpContext, IrpContext->pOriginalIrp, IrpContext->TxMdl );
  1277. SendNow( IrpContext );
  1278. } else {
  1279. IrpContext->Specific.Read.DataReceived = FALSE;
  1280. //
  1281. // Verify burst read will send a missing data request if one we
  1282. // have not received all of the data.
  1283. //
  1284. if ( VerifyBurstRead( IrpContext ) ) {
  1285. NwSetIrpContextEvent( IrpContext );
  1286. }
  1287. }
  1288. Stats.PacketBurstReadTimeouts++;
  1289. }
  1290. NTSTATUS
  1291. ResubmitBurstRead (
  1292. IN PIRP_CONTEXT IrpContext
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. This routine handles a rerouted burst read. The burst request is
  1297. resubmitted on a new burst connection.
  1298. Arguments:*
  1299. pIrpContext - A pointer to the context information for this IRP.
  1300. Return Value:
  1301. None.
  1302. --*/
  1303. {
  1304. NTSTATUS Status;
  1305. ULONG Length, DataMdlBytes = 0 ;
  1306. PMDL DataMdl ;
  1307. DebugTrace( 0, Dbg, "ResubmitBurstRead\n", 0 );
  1308. //
  1309. // Recalculate the burst size, as MaxReceiveSize may have changed.
  1310. //
  1311. Length = MIN( IrpContext->pNpScb->MaxReceiveSize,
  1312. IrpContext->Specific.Read.RemainingLength );
  1313. //
  1314. // Make sure we dont ask for more than bytes described by MDL
  1315. //
  1316. DataMdl = IrpContext->Specific.Read.FullMdl;
  1317. while (DataMdl) {
  1318. DataMdlBytes += MmGetMdlByteCount( DataMdl );
  1319. DataMdl = DataMdl->Next;
  1320. }
  1321. Length = MIN( Length, DataMdlBytes ) ;
  1322. DebugTrace( 0, Dbg, "Requesting another burst, length = %ld\n", Length);
  1323. ASSERT( Length != 0 );
  1324. //
  1325. // Free the packet list, and reset all of the current burst context
  1326. // information.
  1327. //
  1328. FreePacketList( IrpContext );
  1329. IrpContext->Specific.Read.LastReadLength = Length;
  1330. IrpContext->Specific.Read.BurstRequestOffset = 0;
  1331. IrpContext->Specific.Read.BurstSize = 0;
  1332. IrpContext->Specific.Read.DataReceived = FALSE;
  1333. SetConnectionTimeout( IrpContext->pNpScb, Length );
  1334. //
  1335. // Format and send the request.
  1336. //
  1337. BuildBurstReadRequest(
  1338. IrpContext,
  1339. *(ULONG UNALIGNED *)(&IrpContext->Icb->Handle[2]),
  1340. IrpContext->Specific.Read.FileOffset,
  1341. Length );
  1342. // Avoid SendNow setting the RetryCount back to the default
  1343. SetFlag( IrpContext->Flags, IRP_FLAG_RETRY_SEND );
  1344. Status = PrepareAndSendPacket( IrpContext );
  1345. return Status;
  1346. }
  1347. VOID
  1348. RecordPacketReceipt(
  1349. PIRP_CONTEXT IrpContext,
  1350. PVOID ReadData,
  1351. ULONG DataOffset,
  1352. USHORT ByteCount,
  1353. BOOLEAN CopyData
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. This routine records the reciept of a burst read packet. It allocates
  1358. a burst read entry to record data start and length, and then inserts
  1359. the structure in order in the list of packets received for this burst.
  1360. It then copies the data to the user buffer.
  1361. This routine could release the spin lock before doing the
  1362. data copy. Would this be useful?
  1363. Arguments:
  1364. IrpContext - A pointer to IRP context information for this request.
  1365. ReadData - A pointer to the data to copy.
  1366. DataOffset - The start offset of the data in the received packet.
  1367. ByteCount - The amount of data received.
  1368. CopyData - If FALSE, don't copy the data to the user's buffer. The
  1369. transport will do it.
  1370. Return Value:
  1371. None.
  1372. --*/
  1373. {
  1374. PBURST_READ_ENTRY BurstReadEntry;
  1375. PBURST_READ_ENTRY ThisBurstReadEntry, NextBurstReadEntry;
  1376. PLIST_ENTRY ListEntry;
  1377. #if NWDBG
  1378. BOOLEAN Insert = FALSE;
  1379. #endif
  1380. USHORT ExtraBytes;
  1381. DebugTrace(0, Dbg, "RecordPacketReceipt\n", 0 );
  1382. IrpContext->Specific.Read.DataReceived = TRUE;
  1383. //
  1384. // Allocate and initialize a burst read entry.
  1385. //
  1386. BurstReadEntry = ALLOCATE_POOL( NonPagedPool, sizeof( BURST_READ_ENTRY ) );
  1387. if ( BurstReadEntry == NULL ) {
  1388. DebugTrace(0, Dbg, "Failed to allocate BurstReadEntry\n", 0 );
  1389. return;
  1390. }
  1391. //
  1392. // Insert this element in the ordered list of received packets.
  1393. //
  1394. if ( IsListEmpty( &IrpContext->Specific.Read.PacketList ) ) {
  1395. #if NWDBG
  1396. Insert = TRUE;
  1397. #endif
  1398. InsertHeadList(
  1399. &IrpContext->Specific.Read.PacketList,
  1400. &BurstReadEntry->ListEntry );
  1401. DebugTrace(0, Dbg, "First packet in the list\n", 0 );
  1402. } else {
  1403. //
  1404. // Walk the list of received packets, looking for the place to
  1405. // insert this entry. Walk the list backwards, since most of
  1406. // the time we will be appending to the list.
  1407. //
  1408. ListEntry = IrpContext->Specific.Read.PacketList.Blink;
  1409. ThisBurstReadEntry = NULL;
  1410. while ( ListEntry != &IrpContext->Specific.Read.PacketList ) {
  1411. NextBurstReadEntry = ThisBurstReadEntry;
  1412. ThisBurstReadEntry = CONTAINING_RECORD(
  1413. ListEntry,
  1414. BURST_READ_ENTRY,
  1415. ListEntry );
  1416. if ( ThisBurstReadEntry->DataOffset <= DataOffset ) {
  1417. //
  1418. // Found the place in the list to insert this entry.
  1419. //
  1420. if ( ThisBurstReadEntry->DataOffset +
  1421. ThisBurstReadEntry->ByteCount > DataOffset ) {
  1422. //
  1423. // The start of this packet contains data which
  1424. // overlaps data we have received. Chuck the extra
  1425. // data.
  1426. //
  1427. ExtraBytes = (USHORT)( ThisBurstReadEntry->DataOffset +
  1428. ThisBurstReadEntry->ByteCount - DataOffset );
  1429. if ( ExtraBytes < ByteCount ) {
  1430. DataOffset += ExtraBytes;
  1431. (PCHAR)ReadData += ExtraBytes;
  1432. ByteCount -= ExtraBytes;
  1433. } else {
  1434. ByteCount = 0;
  1435. }
  1436. }
  1437. if ( NextBurstReadEntry != NULL &&
  1438. DataOffset + ByteCount > NextBurstReadEntry->DataOffset ) {
  1439. //
  1440. // This packet contains some new data, but some of it
  1441. // overlaps the NextBurstReadEntry. Simply ignore
  1442. // the overlap by adjusting the byte count.
  1443. //
  1444. // If the packet is all overlap, toss it.
  1445. //
  1446. ByteCount = (USHORT)( NextBurstReadEntry->DataOffset - DataOffset );
  1447. }
  1448. if ( ByteCount == 0 ) {
  1449. FREE_POOL( BurstReadEntry );
  1450. return;
  1451. }
  1452. #if NWDBG
  1453. Insert = TRUE;
  1454. #endif
  1455. InsertHeadList( ListEntry, &BurstReadEntry->ListEntry );
  1456. break;
  1457. } else {
  1458. ListEntry = ListEntry->Blink;
  1459. }
  1460. }
  1461. //
  1462. // Couldn't find the place to insert
  1463. //
  1464. ASSERT( Insert );
  1465. }
  1466. BurstReadEntry->DataOffset = DataOffset;
  1467. BurstReadEntry->ByteCount = ByteCount;
  1468. //
  1469. // Copy the data to our read buffer.
  1470. //
  1471. if ( CopyData ) {
  1472. CopyBufferToMdl(
  1473. IrpContext->Specific.Read.FullMdl,
  1474. DataOffset,
  1475. ReadData,
  1476. ByteCount );
  1477. }
  1478. return;
  1479. }
  1480. #include <packon.h>
  1481. typedef struct _MISSING_DATA_ENTRY {
  1482. ULONG DataOffset;
  1483. USHORT ByteCount;
  1484. } MISSING_DATA_ENTRY, *PMISSING_DATA_ENTRY;
  1485. #include <packoff.h>
  1486. BOOLEAN
  1487. VerifyBurstRead(
  1488. PIRP_CONTEXT IrpContext
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. This routine verifies the set of response to a burst read request.
  1493. If some data is missing a missing packet request is sent.
  1494. Arguments:
  1495. IrpContext - A pointer to IRP context information for this request.
  1496. Return Value:
  1497. TRUE - All the data was received.
  1498. FALSE - Some data was missing.
  1499. --*/
  1500. {
  1501. ULONG CurrentOffset = 0;
  1502. PLIST_ENTRY ListEntry;
  1503. PBURST_READ_ENTRY BurstReadEntry;
  1504. USHORT MissingFragmentCount = 0;
  1505. USHORT ByteCount;
  1506. ULONG DataOffset;
  1507. MISSING_DATA_ENTRY UNALIGNED *MissingDataEntry;
  1508. KIRQL OldIrql;
  1509. DebugTrace(+1, Dbg, "VerifyBurstRead\n", 0 );
  1510. //
  1511. // Acquire the SCB spin lock to protect access to the list
  1512. // of received data for this read.
  1513. //
  1514. KeAcquireSpinLock(&IrpContext->pNpScb->NpScbSpinLock, &OldIrql);
  1515. #ifdef NWDBG
  1516. //
  1517. // Verify that the list is in order.
  1518. //
  1519. ListEntry = IrpContext->Specific.Read.PacketList.Flink;
  1520. while ( ListEntry != &IrpContext->Specific.Read.PacketList ) {
  1521. BurstReadEntry = CONTAINING_RECORD( ListEntry, BURST_READ_ENTRY, ListEntry );
  1522. ASSERT ( BurstReadEntry->DataOffset >= CurrentOffset);
  1523. CurrentOffset = BurstReadEntry->DataOffset + BurstReadEntry->ByteCount;
  1524. ListEntry = ListEntry->Flink;
  1525. }
  1526. CurrentOffset = 0;
  1527. #endif
  1528. ListEntry = IrpContext->Specific.Read.PacketList.Flink;
  1529. while ( ListEntry != &IrpContext->Specific.Read.PacketList ) {
  1530. BurstReadEntry = CONTAINING_RECORD( ListEntry, BURST_READ_ENTRY, ListEntry );
  1531. if ( BurstReadEntry->DataOffset != CurrentOffset) {
  1532. //
  1533. // There is a hole in the data, fill in a missing packet entry.
  1534. //
  1535. MissingDataEntry = (MISSING_DATA_ENTRY UNALIGNED *)
  1536. &IrpContext->req[ sizeof( NCP_BURST_HEADER ) +
  1537. MissingFragmentCount * sizeof( MISSING_DATA_ENTRY ) ];
  1538. DataOffset = CurrentOffset + SIZE_ADJUST( IrpContext );
  1539. LongByteSwap( MissingDataEntry->DataOffset, DataOffset );
  1540. ByteCount = (USHORT)( BurstReadEntry->DataOffset - CurrentOffset );
  1541. ShortByteSwap( MissingDataEntry->ByteCount, ByteCount );
  1542. ASSERT( BurstReadEntry->DataOffset - CurrentOffset <= IrpContext->pNpScb->MaxReceiveSize );
  1543. DebugTrace(0, Dbg, "Missing data at offset %ld\n", DataOffset );
  1544. DebugTrace(0, Dbg, "Missing %d bytes\n", ByteCount );
  1545. DebugTrace(0, Dbg, "CurrentOffset: %d\n", CurrentOffset );
  1546. MissingFragmentCount++;
  1547. }
  1548. CurrentOffset = BurstReadEntry->DataOffset + BurstReadEntry->ByteCount;
  1549. ListEntry = ListEntry->Flink;
  1550. }
  1551. //
  1552. // Any data missing off the end?
  1553. //
  1554. if ( CurrentOffset <
  1555. IrpContext->Specific.Read.BurstSize ) {
  1556. //
  1557. // There is a hole in the data, fill in a missing packet entry.
  1558. //
  1559. MissingDataEntry = (PMISSING_DATA_ENTRY)
  1560. &IrpContext->req[ sizeof( NCP_BURST_HEADER ) +
  1561. MissingFragmentCount * sizeof( MISSING_DATA_ENTRY ) ];
  1562. DataOffset = CurrentOffset + SIZE_ADJUST( IrpContext );
  1563. LongByteSwap( MissingDataEntry->DataOffset, DataOffset );
  1564. ByteCount = (USHORT)( IrpContext->Specific.Read.BurstSize - CurrentOffset );
  1565. ShortByteSwap( MissingDataEntry->ByteCount, ByteCount );
  1566. ASSERT( IrpContext->Specific.Read.BurstSize - CurrentOffset < IrpContext->pNpScb->MaxReceiveSize );
  1567. DebugTrace(0, Dbg, "Missing data at offset %ld\n", MissingDataEntry->DataOffset );
  1568. DebugTrace(0, Dbg, "Missing %d bytes\n", MissingDataEntry->ByteCount );
  1569. MissingFragmentCount++;
  1570. }
  1571. if ( MissingFragmentCount == 0 ) {
  1572. //
  1573. // This read is now complete. Don't process any more packets until
  1574. // the next packet is sent.
  1575. //
  1576. IrpContext->pNpScb->OkToReceive = FALSE;
  1577. KeReleaseSpinLock(&IrpContext->pNpScb->NpScbSpinLock, OldIrql);
  1578. DebugTrace(-1, Dbg, "VerifyBurstRead -> TRUE\n", 0 );
  1579. return( TRUE );
  1580. } else {
  1581. KeReleaseSpinLock(&IrpContext->pNpScb->NpScbSpinLock, OldIrql);
  1582. //
  1583. // The server dropped a packet, adjust the timers.
  1584. //
  1585. NwProcessReceiveBurstFailure( IrpContext->pNpScb, MissingFragmentCount );
  1586. //
  1587. // Request the missing data.
  1588. //
  1589. SetFlag( IrpContext->Flags, IRP_FLAG_BURST_PACKET );
  1590. //
  1591. // Update burst request offset since we are about to request
  1592. // more data. Note that this will reset the retry count,
  1593. // thus giving the server full timeout time to return the
  1594. // missing data.
  1595. //
  1596. BuildRequestPacket(
  1597. IrpContext,
  1598. BurstReadCallback,
  1599. "Bws",
  1600. 0, // Frame size for this request is 0
  1601. 0, // Offset of data
  1602. BURST_FLAG_SYSTEM_PACKET,
  1603. MissingFragmentCount,
  1604. MissingFragmentCount * sizeof( MISSING_DATA_ENTRY )
  1605. );
  1606. PrepareAndSendPacket( IrpContext );
  1607. Stats.PacketBurstReadTimeouts++;
  1608. DebugTrace(-1, Dbg, "VerifyBurstRead -> FALSE\n", 0 );
  1609. return( FALSE );
  1610. }
  1611. }
  1612. VOID
  1613. FreePacketList(
  1614. PIRP_CONTEXT IrpContext
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. This routine frees the received packet list for a burst read.
  1619. Arguments:
  1620. IrpContext - A pointer to IRP context information for this request.
  1621. Return Value:
  1622. None.
  1623. --*/
  1624. {
  1625. PLIST_ENTRY ListHead;
  1626. PBURST_READ_ENTRY BurstReadEntry;
  1627. ListHead = &IrpContext->Specific.Read.PacketList;
  1628. while ( !IsListEmpty( ListHead ) ) {
  1629. BurstReadEntry = CONTAINING_RECORD( ListHead->Flink, BURST_READ_ENTRY, ListEntry );
  1630. RemoveHeadList( ListHead );
  1631. FREE_POOL( BurstReadEntry );
  1632. }
  1633. }
  1634. NTSTATUS
  1635. BurstReadReceive(
  1636. IN PIRP_CONTEXT IrpContext,
  1637. IN ULONG BytesAvailable,
  1638. IN PULONG BytesAccepted,
  1639. IN PUCHAR Response,
  1640. PMDL *pReceiveMdl
  1641. )
  1642. /*++
  1643. Routine Description:
  1644. This routine builds an MDL to receive burst read data. This routine
  1645. is called at data indication time.
  1646. This routine is called with the non paged SCB spin lock held.
  1647. Arguments:
  1648. IrpContext - A pointer to IRP context information for this request.
  1649. BytesAvailable - The number of bytes in the entire packet.
  1650. BytesAccepted - Returns the number of bytes accepted from the packet.
  1651. Response - A pointer to the indication buffer.
  1652. Return Value:
  1653. Mdl - An MDL to receive the data.
  1654. This routine raise an exception if it cannot receive the data.
  1655. --*/
  1656. {
  1657. NTSTATUS Status;
  1658. ULONG DataOffset;
  1659. ULONG TotalBytesRead;
  1660. PUCHAR ReadData;
  1661. USHORT BytesThisPacket;
  1662. UCHAR Flags;
  1663. PMDL PartialMdl;
  1664. DebugTrace(0, Dbg, "Burst read receive\n", 0);
  1665. Status = ParseBurstReadResponse(
  1666. IrpContext,
  1667. Response,
  1668. BytesAvailable,
  1669. &Flags,
  1670. &DataOffset,
  1671. &BytesThisPacket,
  1672. &ReadData,
  1673. &TotalBytesRead );
  1674. if ( !NT_SUCCESS( Status ) ) {
  1675. DebugTrace(0, Dbg, "Failed to parse burst read response\n", 0);
  1676. return Status;
  1677. }
  1678. //
  1679. // We can accept up to the size of a burst read header, plus
  1680. // 3 bytes of fluff for the unaligned read case.
  1681. //
  1682. *BytesAccepted = (ULONG) (ReadData - Response);
  1683. ASSERT( *BytesAccepted <= sizeof(NCP_BURST_READ_RESPONSE) + 3 );
  1684. RecordPacketReceipt( IrpContext, ReadData, DataOffset, BytesThisPacket, FALSE );
  1685. IrpContext->Specific.Read.Flags = Flags;
  1686. //
  1687. // If we did a read at EOF the netware server will return 0 bytes read,
  1688. // no error.
  1689. //
  1690. ASSERT( IrpContext->Specific.Read.FullMdl != NULL );
  1691. if ( BytesThisPacket > 0 ) {
  1692. PartialMdl = AllocateReceivePartialMdl(
  1693. IrpContext->Specific.Read.FullMdl,
  1694. DataOffset,
  1695. BytesThisPacket );
  1696. if ( !PartialMdl ) {
  1697. IrpContext->Specific.Read.Status = STATUS_INSUFFICIENT_RESOURCES;
  1698. }
  1699. // Record Mdl to free when CopyIndicatedData or Irp completed.
  1700. IrpContext->Specific.Read.PartialMdl = PartialMdl;
  1701. } else {
  1702. PartialMdl = NULL;
  1703. }
  1704. *pReceiveMdl = PartialMdl;
  1705. return( STATUS_SUCCESS );
  1706. }
  1707. NTSTATUS
  1708. ParseBurstReadResponse(
  1709. IN PIRP_CONTEXT IrpContext,
  1710. PUCHAR Response,
  1711. ULONG BytesAvailable,
  1712. PUCHAR Flags,
  1713. PULONG DataOffset,
  1714. PUSHORT BytesThisPacket,
  1715. PUCHAR *ReadData,
  1716. PULONG TotalBytesRead
  1717. )
  1718. /*++
  1719. Routine Description:
  1720. This routine parses a burst read response.
  1721. This routine must be called the the nonpagd SCB spinlock held.
  1722. Arguments:
  1723. IrpContext - A pointer to IRP context information for this request.
  1724. Response - A pointer to the response buffer.
  1725. BytesAvailable - The number of bytes in the packet.
  1726. Flags - Returns the Burst Flags
  1727. DataOffset - Returns the data offset (within the burst) of the
  1728. data in this packet.
  1729. BytesThisPacket - Returns the number of file data bytes in this packet.
  1730. ReadData - Returns a pointer to the start of the file data in the
  1731. packet buffer.
  1732. TotalBytesRead - Returns the number of byte of file data in the
  1733. entire burst.
  1734. Return Value:
  1735. The status of the read.
  1736. --*/
  1737. {
  1738. NTSTATUS Status;
  1739. ULONG Result;
  1740. PNCP_BURST_READ_RESPONSE ReadResponse;
  1741. DebugTrace(+1, Dbg, "ParseBurstReadResponse\n", 0);
  1742. ReadResponse = (PNCP_BURST_READ_RESPONSE)Response;
  1743. *Flags = ReadResponse->BurstHeader.Flags;
  1744. #ifdef NWDBG
  1745. //
  1746. // Bad net simulator.
  1747. //
  1748. if ( DropReadPackets != 0 ) {
  1749. if ( ( rand() % DropReadPackets ) == 0 ) {
  1750. IrpContext->pNpScb->OkToReceive = TRUE;
  1751. DebugTrace( 0, Dbg, "Dropping packet\n", 0 );
  1752. DebugTrace( -1, Dbg, "ParseBurstReadResponse -> %X\n", STATUS_UNSUCCESSFUL );
  1753. return ( STATUS_UNSUCCESSFUL );
  1754. }
  1755. }
  1756. #endif
  1757. //
  1758. // If this isn't the last packet, setup for the next burst packet.
  1759. //
  1760. if ( !FlagOn( *Flags, BURST_FLAG_END_OF_BURST ) ) {
  1761. DebugTrace(0, Dbg, "Waiting for another packet\n", 0);
  1762. //
  1763. // Once we receive the first packet in a read response be aggresive
  1764. // about timing out while waiting for the rest of the burst.
  1765. //
  1766. IrpContext->pNpScb->TimeOut = IrpContext->pNpScb->SendTimeout ;
  1767. IrpContext->pNpScb->OkToReceive = TRUE;
  1768. }
  1769. LongByteSwap( *DataOffset, ReadResponse->BurstHeader.BurstOffset );
  1770. ShortByteSwap( *BytesThisPacket, ReadResponse->BurstHeader.BurstLength );
  1771. //
  1772. // How much data was received?
  1773. //
  1774. if ( IsListEmpty( &IrpContext->Specific.Read.PacketList ) ) {
  1775. DebugTrace(0, Dbg, "Expecting initial response\n", 0);
  1776. //
  1777. // This is the initial burst response packet.
  1778. //
  1779. if ( *DataOffset != 0 ) {
  1780. DebugTrace(0, Dbg, "Invalid initial response tossed\n", 0);
  1781. //
  1782. // This is actually a subsequent response. Toss it.
  1783. //
  1784. DebugTrace( -1, Dbg, "ParseBurstReadResponse -> %X\n", STATUS_UNSUCCESSFUL );
  1785. IrpContext->pNpScb->OkToReceive = TRUE;
  1786. return ( STATUS_UNSUCCESSFUL );
  1787. }
  1788. Result = ReadResponse->Result;
  1789. LongByteSwap( *TotalBytesRead, ReadResponse->BytesRead );
  1790. Status = NwBurstResultToNtStatus( Result );
  1791. IrpContext->Specific.Read.Status = Status;
  1792. if ( !NT_SUCCESS( Status ) ) {
  1793. //
  1794. // Update the burst request number now.
  1795. //
  1796. DebugTrace(0, Dbg, "Read completed, error = %X\n", Status );
  1797. ClearFlag( IrpContext->Flags, IRP_FLAG_BURST_REQUEST );
  1798. NwSetIrpContextEvent( IrpContext );
  1799. DebugTrace( -1, Dbg, "ParseBurstReadResponse -> %X\n", Status );
  1800. return( Status );
  1801. }
  1802. if ( Result == 3 || *BytesThisPacket < 8 ) { // No data
  1803. *TotalBytesRead = 0;
  1804. *BytesThisPacket = 8;
  1805. }
  1806. *ReadData = Response + sizeof(NCP_BURST_READ_RESPONSE);
  1807. IrpContext->Specific.Read.BurstSize = *TotalBytesRead;
  1808. //
  1809. // Bytes this packet includes a LONG status and a LONG byte total.
  1810. // Adjust the count to reflect the number of data bytes actually
  1811. // shipped.
  1812. //
  1813. *BytesThisPacket -= sizeof( ULONG ) + sizeof( ULONG );
  1814. //
  1815. // Adjust this data if the read was not DWORD aligned.
  1816. //
  1817. if ( (IrpContext->Specific.Read.FileOffset & 0x03) != 0
  1818. && *BytesThisPacket != 0 ) {
  1819. *ReadData += IrpContext->Specific.Read.FileOffset & 0x03;
  1820. *BytesThisPacket -= (USHORT)IrpContext->Specific.Read.FileOffset & 0x03;
  1821. }
  1822. DebugTrace(0, Dbg, "Initial response\n", 0);
  1823. DebugTrace(0, Dbg, "Result = %ld\n", Result);
  1824. DebugTrace(0, Dbg, "Total bytes read = %ld\n", *TotalBytesRead );
  1825. } else {
  1826. //
  1827. // Intermediate response packet.
  1828. //
  1829. *ReadData = Response + sizeof( NCP_BURST_HEADER );
  1830. *DataOffset -= SIZE_ADJUST( IrpContext );
  1831. }
  1832. DebugTrace(0, Dbg, "DataOffset = %ld\n", *DataOffset );
  1833. DebugTrace(0, Dbg, "# bytes received = %d\n", *BytesThisPacket );
  1834. if ( *DataOffset > IrpContext->Specific.Read.BurstSize ||
  1835. *DataOffset + *BytesThisPacket > IrpContext->Specific.Read.BurstSize ) {
  1836. DebugTrace(0, Dbg, "Invalid response tossed\n", 0);
  1837. DebugTrace( -1, Dbg, "ParseBurstReadResponse -> %X\n", STATUS_SUCCESS );
  1838. IrpContext->pNpScb->OkToReceive = TRUE;
  1839. return ( STATUS_UNSUCCESSFUL );
  1840. }
  1841. DebugTrace( -1, Dbg, "ParseBurstReadResponse -> %X\n", STATUS_SUCCESS );
  1842. return( STATUS_SUCCESS );
  1843. }
  1844. PMDL
  1845. AllocateReceivePartialMdl(
  1846. PMDL FullMdl,
  1847. ULONG DataOffset,
  1848. ULONG BytesThisPacket
  1849. )
  1850. /*++
  1851. Routine Description:
  1852. This routine allocates a partial MDL to receive read data. This
  1853. routine is called at receive indication time.
  1854. Arguments:
  1855. FullMdl - The FullMdl for the buffer.
  1856. DataOffset - The offset into the buffer where the data is to be received.
  1857. BytesThisPacket - The number of data bytes to be received into the buffer.
  1858. Return Value:
  1859. MDL - A pointer to an MDL to receive the data
  1860. This routine raises an exception if it cannot allocate an MDL.
  1861. --*/
  1862. {
  1863. NTSTATUS Status = STATUS_SUCCESS;
  1864. PUCHAR BufferStart, BufferEnd;
  1865. PMDL InitialMdl, NextMdl;
  1866. PMDL ReceiveMdl, PreviousReceiveMdl;
  1867. ULONG BytesThisMdl;
  1868. BufferStart = (PUCHAR)MmGetMdlVirtualAddress( FullMdl ) + DataOffset;
  1869. BufferEnd = (PUCHAR)MmGetMdlVirtualAddress( FullMdl ) +
  1870. MmGetMdlByteCount( FullMdl );
  1871. //
  1872. // Walk the MDL chain look for the MDL for the actual buffer for the
  1873. // start of this data.
  1874. //
  1875. while ( BufferStart >= BufferEnd ) {
  1876. DataOffset -= MmGetMdlByteCount( FullMdl );
  1877. FullMdl = FullMdl->Next;
  1878. //
  1879. // if more data than expected, dont dereference NULL! see next loop.
  1880. //
  1881. if (!FullMdl) {
  1882. ASSERT(FALSE) ;
  1883. break ;
  1884. }
  1885. BufferStart = (PUCHAR)MmGetMdlVirtualAddress( FullMdl ) + DataOffset;
  1886. BufferEnd = (PUCHAR)MmGetMdlVirtualAddress( FullMdl ) +
  1887. MmGetMdlByteCount( FullMdl );
  1888. }
  1889. PreviousReceiveMdl = NULL;
  1890. InitialMdl = NULL;
  1891. BytesThisMdl = (ULONG)(BufferEnd - BufferStart);
  1892. //
  1893. // Check FullMdl to cover the case where the server returns more data
  1894. // than requested.
  1895. //
  1896. while (( BytesThisPacket != 0 ) &&
  1897. ( FullMdl != NULL )) {
  1898. BytesThisMdl = MIN( BytesThisMdl, BytesThisPacket );
  1899. //
  1900. // Some of the data fits in the first part of the MDL;
  1901. //
  1902. ReceiveMdl = ALLOCATE_MDL(
  1903. BufferStart,
  1904. BytesThisMdl,
  1905. FALSE,
  1906. FALSE,
  1907. NULL );
  1908. if ( ReceiveMdl == NULL ) {
  1909. Status = STATUS_INSUFFICIENT_RESOURCES;
  1910. break;
  1911. }
  1912. if ( InitialMdl == NULL ) {
  1913. InitialMdl = ReceiveMdl;
  1914. }
  1915. IoBuildPartialMdl(
  1916. FullMdl,
  1917. ReceiveMdl,
  1918. BufferStart,
  1919. BytesThisMdl );
  1920. if ( PreviousReceiveMdl != NULL ) {
  1921. PreviousReceiveMdl->Next = ReceiveMdl;
  1922. }
  1923. PreviousReceiveMdl = ReceiveMdl;
  1924. BytesThisPacket -= BytesThisMdl;
  1925. FullMdl = FullMdl->Next;
  1926. if ( FullMdl != NULL) {
  1927. BytesThisMdl = MmGetMdlByteCount( FullMdl );
  1928. BufferStart = MmGetMdlVirtualAddress( FullMdl );
  1929. }
  1930. }
  1931. if ( Status == STATUS_INSUFFICIENT_RESOURCES ) {
  1932. //
  1933. // Cleanup allocated MDLs
  1934. //
  1935. while ( InitialMdl != NULL ) {
  1936. NextMdl = InitialMdl->Next;
  1937. FREE_MDL( InitialMdl );
  1938. InitialMdl = NextMdl;
  1939. }
  1940. DebugTrace( 0, Dbg, "AllocateReceivePartialMdl Failed\n", 0 );
  1941. }
  1942. DebugTrace( 0, Dbg, "AllocateReceivePartialMdl -> %08lX\n", InitialMdl );
  1943. return( InitialMdl );
  1944. }
  1945. VOID
  1946. SetConnectionTimeout(
  1947. PNONPAGED_SCB pNpScb,
  1948. ULONG Length
  1949. )
  1950. /*++
  1951. Routine Description:
  1952. The server will pause NwReceiveDelay between packets. Make sure we have our timeout
  1953. so that we will take that into account.
  1954. Arguments:
  1955. pNpScb - Connection
  1956. Length - Length of the burst in bytes
  1957. Return Value:
  1958. None.
  1959. --*/
  1960. {
  1961. ULONG TimeInNwUnits;
  1962. LONG SingleTimeInNwUnits;
  1963. SingleTimeInNwUnits = pNpScb->NwSingleBurstPacketTime + pNpScb->NwReceiveDelay;
  1964. TimeInNwUnits = SingleTimeInNwUnits * ((Length / pNpScb->MaxPacketSize) + 1) +
  1965. pNpScb->NwLoopTime;
  1966. //
  1967. // Convert to 1/18ths of a second ticks and multiply by a fudge
  1968. // factor. The fudge factor is expressed as a percentage. 100 will
  1969. // mean no fudge.
  1970. //
  1971. pNpScb->MaxTimeOut = (SHORT)( ((TimeInNwUnits / 555) *
  1972. (ULONG)ReadTimeoutMultiplier) / 100 + 1);
  1973. //
  1974. // Now make sure we have a meaningful lower and upper limit.
  1975. //
  1976. if (pNpScb->MaxTimeOut < 2)
  1977. {
  1978. pNpScb->MaxTimeOut = 2 ;
  1979. }
  1980. if (pNpScb->MaxTimeOut > (SHORT)MaxReadTimeout)
  1981. {
  1982. pNpScb->MaxTimeOut = (SHORT)MaxReadTimeout ;
  1983. }
  1984. pNpScb->TimeOut = pNpScb->SendTimeout = pNpScb->MaxTimeOut;
  1985. DebugTrace( 0, DEBUG_TRACE_LIP, "pNpScb->MaxTimeout = %08lx\n", pNpScb->MaxTimeOut );
  1986. }
  1987. #if NWFASTIO
  1988. BOOLEAN
  1989. NwFastRead (
  1990. IN PFILE_OBJECT FileObject,
  1991. IN PLARGE_INTEGER FileOffset,
  1992. IN ULONG Length,
  1993. IN BOOLEAN Wait,
  1994. IN ULONG LockKey,
  1995. OUT PVOID Buffer,
  1996. OUT PIO_STATUS_BLOCK IoStatus,
  1997. IN PDEVICE_OBJECT DeviceObject
  1998. )
  1999. /*++
  2000. Routine Description:
  2001. This routine does a fast cached read bypassing the usual file system
  2002. entry routine (i.e., without the Irp). It is used to do a copy read
  2003. of a cached file object. For a complete description of the arguments
  2004. see CcCopyRead.
  2005. Arguments:
  2006. FileObject - Pointer to the file object being read.
  2007. FileOffset - Byte offset in file for desired data.
  2008. Length - Length of desired data in bytes.
  2009. Wait - FALSE if caller may not block, TRUE otherwise
  2010. Buffer - Pointer to output buffer to which data should be copied.
  2011. IoStatus - Pointer to standard I/O status block to receive the status
  2012. for the transfer.
  2013. Return Value:
  2014. FALSE - if Wait was supplied as FALSE and the data was not delivered, or
  2015. if there is an I/O error.
  2016. TRUE - if the data is being delivered
  2017. --*/
  2018. {
  2019. NODE_TYPE_CODE nodeTypeCode;
  2020. PICB icb;
  2021. PFCB fcb;
  2022. PVOID fsContext;
  2023. ULONG bytesRead;
  2024. ULONG offset;
  2025. try {
  2026. FsRtlEnterFileSystem();
  2027. DebugTrace(+1, Dbg, "NwFastRead...\n", 0);
  2028. //
  2029. // Special case a read of zero length
  2030. //
  2031. if (Length == 0) {
  2032. //
  2033. // A zero length transfer was requested.
  2034. //
  2035. IoStatus->Status = STATUS_SUCCESS;
  2036. IoStatus->Information = 0;
  2037. DebugTrace(+1, Dbg, "NwFastRead -> TRUE\n", 0);
  2038. return TRUE;
  2039. }
  2040. //
  2041. // Decode the file object to figure out who we are. If the result
  2042. // is not FCB then its an illegal parameter.
  2043. //
  2044. if ((nodeTypeCode = NwDecodeFileObject( FileObject,
  2045. &fsContext,
  2046. (PVOID *)&icb )) != NW_NTC_ICB) {
  2047. DebugTrace(0, Dbg, "Not a file\n", 0);
  2048. DebugTrace(-1, Dbg, "NwFastRead -> FALSE\n", 0);
  2049. return FALSE;
  2050. }
  2051. fcb = (PFCB)icb->SuperType.Fcb;
  2052. nodeTypeCode = fcb->NodeTypeCode;
  2053. offset = FileOffset->LowPart;
  2054. bytesRead = CacheRead(
  2055. fcb->NonPagedFcb,
  2056. offset,
  2057. Length,
  2058. Buffer,
  2059. TRUE );
  2060. if ( bytesRead != 0 ) {
  2061. ASSERT( bytesRead == Length );
  2062. IoStatus->Status = STATUS_SUCCESS;
  2063. IoStatus->Information = bytesRead;
  2064. #ifndef NT1057
  2065. FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + bytesRead;
  2066. #endif
  2067. DebugTrace(-1, Dbg, "NwFastRead -> TRUE\n", 0);
  2068. return( TRUE );
  2069. } else {
  2070. DebugTrace(-1, Dbg, "NwFastRead -> FALSE\n", 0);
  2071. return( FALSE );
  2072. }
  2073. } finally {
  2074. FsRtlExitFileSystem();
  2075. }
  2076. }
  2077. #endif