|
|
/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
receive.c
Abstract:
Implement the TDI_RECEIVE for session service
Author:
Jiandong Ruan
Revision History:
--*/ #include "precomp.h"
#include "receive.tmh"
VOID SmbCancelReceive( IN PDEVICE_OBJECT Device, IN PIRP Irp ) { PIO_STACK_LOCATION IrpSp; PSMB_CONNECT ConnectObject; PLIST_ENTRY Entry; PIRP RcvIrp; KIRQL Irql;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (IrpSp->FileObject->FsContext2 != UlongToPtr(SMB_TDI_CONNECT)) { ASSERT(0); return; } ConnectObject = (PSMB_CONNECT)IrpSp->FileObject->FsContext;
IoSetCancelRoutine(Irp, NULL); IoReleaseCancelSpinLock(Irp->CancelIrql); SmbTrace(SMB_TRACE_TCP, ("Cancel Receive Irp %p ConnectObject=%p ClientObject=%p", Irp, ConnectObject, ConnectObject->ClientObject));
PUSH_LOCATION(ConnectObject, 0x800000);
SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql); Entry = ConnectObject->RcvList.Flink; while (Entry != &ConnectObject->RcvList) { RcvIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); if (RcvIrp == Irp) { RemoveEntryList(Entry); InitializeListHead(Entry); SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
PUSH_LOCATION(ConnectObject, 0x800010);
SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE); return; } Entry = Entry->Flink; } SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
ASSERT(0); }
NTSTATUS SmbPullDataFromXport( PSMB_CONNECT ConnectObject ) { return STATUS_SUCCESS; }
int SmbReceivePassNumber = 0;
NTSTATUS SmbReceive( PSMB_DEVICE Device, PIRP Irp ) /*++
Routine Description:
TDI_RECEIVE
Arguments:
Return Value:
--*/ { PIO_STACK_LOCATION IrpSp = NULL; PSMB_CONNECT ConnectObject = NULL; KIRQL Irql; NTSTATUS status = STATUS_PENDING; LONG BytesTaken, ClientBufferSize; PDEVICE_OBJECT TcpDeviceObject = NULL; PFILE_OBJECT TcpFileObject = NULL;
PTDI_REQUEST_KERNEL_RECEIVE ClientRcvParams;
//
// Since I never see this code path covered in my test,
// I put an assert here to get a chance to take a look
// when it is really taken.
//
// Srv.sys does call this function.
SmbReceivePassNumber++;
SmbPrint(SMB_TRACE_CALL, ("SmbReceive\n")); IrpSp = IoGetCurrentIrpStackLocation(Irp); ClientRcvParams = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_RECEIVE); if (NULL == ConnectObject) { ASSERT(0); return STATUS_INVALID_HANDLE; } PUSH_LOCATION(ConnectObject, 0x900000);
if (ConnectObject->State != SMB_CONNECTED) { PUSH_LOCATION(ConnectObject, 0x900020); ASSERT(0); SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE); return STATUS_INVALID_DEVICE_REQUEST; }
//
// Sanity check
//
ClientBufferSize = ClientRcvParams->ReceiveLength; if ((ClientRcvParams->ReceiveFlags & (TDI_RECEIVE_EXPEDITED | TDI_RECEIVE_PEEK)) || Irp->MdlAddress == NULL || ClientBufferSize == 0) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE); return status; }
PUSH_LOCATION(ConnectObject, 0x900030);
SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql); if (NULL == ConnectObject->TcpContext) { SMB_RELEASE_SPINLOCK(ConnectObject, Irql); return STATUS_CONNECTION_RESET; }
if (ConnectObject->StateRcvHandler != SmbPartialRcv || ConnectObject->ClientIrp != NULL) { BREAK_WHEN_TAKE();
//
// Queue the IRP
//
IoAcquireCancelSpinLock(&Irp->CancelIrql); if (!Irp->Cancel) { IoMarkIrpPending(Irp); status = STATUS_PENDING; InsertTailList(&ConnectObject->RcvList, &Irp->Tail.Overlay.ListEntry); IoSetCancelRoutine(Irp, SmbCancelReceive); PUSH_LOCATION(ConnectObject, 0x900040);
} else { status = STATUS_CANCELLED; PUSH_LOCATION(ConnectObject, 0x900050); } IoReleaseCancelSpinLock(Irp->CancelIrql); SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
if (status != STATUS_PENDING) { PUSH_LOCATION(ConnectObject, 0x900060); SmbDereferenceConnect(ConnectObject, SMB_REF_RECEIVE); } return status; }
//
// Client has backlog either in us or in TCP
//
ASSERT(ConnectObject->BytesRemaining > 0); ASSERT(ConnectObject->BytesRemaining <= ConnectObject->CurrentPktLength);
ConnectObject->ClientIrp = Irp; ConnectObject->ClientMdl = Irp->MdlAddress; ConnectObject->ClientBufferSize = ClientBufferSize; ConnectObject->FreeBytesInMdl = ConnectObject->ClientBufferSize;
//
// First, we need to copy the remaining data in the IndicateBuffer if any
//
if (ConnectObject->BytesInIndicate > 0) { PUSH_LOCATION(ConnectObject, 0x900070); // BREAK_WHEN_TAKE();
BytesTaken = 0; IoMarkIrpPending(Irp); status = SmbFillIrp(ConnectObject, ConnectObject->IndicateBuffer, ConnectObject->BytesInIndicate, &BytesTaken); ASSERT(BytesTaken <= ConnectObject->BytesInIndicate); ConnectObject->BytesInIndicate -= BytesTaken;
if (status == STATUS_SUCCESS) { PUSH_LOCATION(ConnectObject, 0x900080); if (ConnectObject->BytesInIndicate) { PUSH_LOCATION(ConnectObject, 0x900090);
//
// The buffer is too small
//
ASSERT(ConnectObject->ClientIrp == NULL); ASSERT(ConnectObject->ClientMdl == NULL);
RtlMoveMemory( ConnectObject->IndicateBuffer + BytesTaken, ConnectObject->IndicateBuffer, ConnectObject->BytesInIndicate ); }
//
// The IRP has been completed by SmbFillIrp. Returning STATUS_PENDING to avoid
// double completion
//
status = STATUS_PENDING; goto cleanup; }
ASSERT (status == STATUS_MORE_PROCESSING_REQUIRED); }
ASSERT (ConnectObject->BytesInIndicate == 0); ASSERT (ConnectObject->ClientIrp); ASSERT (ConnectObject->ClientMdl); ASSERT (IsValidPartialRcvState(ConnectObject));
SmbPrepareReceiveIrp(ConnectObject);
TcpFileObject = ConnectObject->TcpContext->Connect.ConnectObject; TcpDeviceObject = IoGetRelatedDeviceObject(TcpFileObject); ObReferenceObject(TcpFileObject); SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
ConnectObject->PendingIRPs[SMB_PENDING_RECEIVE] = ConnectObject->ClientIrp; IoMarkIrpPending(Irp); status = IoCallDriver(TcpDeviceObject, ConnectObject->ClientIrp); ObDereferenceObject(TcpFileObject);
return STATUS_PENDING;
cleanup: SMB_RELEASE_SPINLOCK(ConnectObject, Irql); return status; }
|