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.
265 lines
7.7 KiB
265 lines
7.7 KiB
/*++
|
|
|
|
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;
|
|
}
|