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.
270 lines
6.8 KiB
270 lines
6.8 KiB
/*++
|
|
|
|
Copyright (c) 1989-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
send.c
|
|
|
|
Abstract:
|
|
|
|
Implement TDI_SEND
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "send.tmh"
|
|
|
|
PMDL
|
|
SmbAllocateNetBuffer(
|
|
ULONG uNumOfBytes
|
|
)
|
|
{
|
|
PVOID pvBuf = NULL;
|
|
PVOID pvMappedBuf = NULL;
|
|
PMDL pMdl = NULL;
|
|
|
|
pvBuf = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
uNumOfBytes,
|
|
NBT_HEADER_TAG
|
|
);
|
|
if (NULL == pvBuf) {
|
|
goto error;
|
|
}
|
|
|
|
pMdl = IoAllocateMdl(pvBuf, uNumOfBytes, FALSE, FALSE, NULL);
|
|
if (NULL == pMdl) {
|
|
ExFreePool(pvBuf);
|
|
goto error;
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool(pMdl);
|
|
|
|
//
|
|
// Verify the mapped system address == pvBuf
|
|
// SmbFreeNetBuffer depends on this assumption.
|
|
//
|
|
|
|
pvMappedBuf = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
|
|
if (pvMappedBuf != pvBuf) {
|
|
ExFreePool(pvBuf);
|
|
IoFreeMdl(pMdl);
|
|
ASSERT(0);
|
|
pMdl = NULL;
|
|
}
|
|
|
|
error:
|
|
return pMdl;
|
|
}
|
|
|
|
VOID
|
|
SmbFreeNetBuffer(
|
|
PMDL pMdl
|
|
)
|
|
{
|
|
PVOID pvBuf = NULL;
|
|
|
|
if (NULL == pMdl) {
|
|
goto error;
|
|
}
|
|
|
|
pvBuf = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
|
|
if (NULL != pvBuf) {
|
|
ExFreePool(pvBuf);
|
|
pvBuf = NULL;
|
|
}
|
|
|
|
IoFreeMdl(pMdl);
|
|
pMdl = NULL;
|
|
|
|
error:
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbSendCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PSMB_CONNECT ConnectObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This the completion routine of sending a packet
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PMDL Mdl;
|
|
|
|
if (Irp->PendingReturned) {
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
Mdl = Irp->MdlAddress;
|
|
|
|
if (Mdl->MdlFlags & MDL_NETWORK_HEADER) {
|
|
(PUCHAR)Mdl->MappedSystemVa += SMB_SESSION_HEADER_SIZE;
|
|
Mdl->ByteOffset += SMB_SESSION_HEADER_SIZE;
|
|
Mdl->ByteCount -= SMB_SESSION_HEADER_SIZE;
|
|
} else {
|
|
ASSERT(NULL != Mdl->Next);
|
|
Irp->MdlAddress = Mdl->Next;
|
|
|
|
ASSERT(MmGetMdlByteCount(Mdl) == SMB_SESSION_HEADER_SIZE);
|
|
SmbFreeNetBuffer(Mdl);
|
|
Mdl = NULL;
|
|
}
|
|
|
|
if (Irp->IoStatus.Status == STATUS_SUCCESS && Irp->IoStatus.Information >= SMB_SESSION_HEADER_SIZE) {
|
|
SmbPrint(SMB_TRACE_TCP, ("SmbSendCompletion: Send %d bytes\n", Irp->IoStatus.Information));
|
|
Irp->IoStatus.Information -= SMB_SESSION_HEADER_SIZE;
|
|
ConnectObject->BytesSent += (ULONG)(Irp->IoStatus.Information);
|
|
} else {
|
|
Irp->IoStatus.Information = 0;
|
|
SmbPrint(SMB_TRACE_TCP, ("SmbSendCompletion: status=0x%08lx\n", Irp->IoStatus.Status));
|
|
ASSERT (Irp->IoStatus.Status != STATUS_CONNECTION_ACTIVE);
|
|
}
|
|
|
|
ConnectObject->PendingIRPs[SMB_PENDING_SEND] = NULL;
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_SEND);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmbSend(
|
|
PSMB_DEVICE Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TDI_SEND
|
|
RDR/SRV is using backfill mode only at this time. So non-backfill mode is postponed.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
PTDI_REQUEST_KERNEL_SEND TdiRequest = NULL;
|
|
PMDL Mdl = NULL;
|
|
PSMB_CONNECT ConnectObject = NULL;
|
|
PULONG SmbHdr = NULL;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
PFILE_OBJECT FileObject = NULL;
|
|
DWORD SendLength = 0;
|
|
KIRQL Irql;
|
|
PMDL pMdlNbtHdr = NULL;
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
TdiRequest = (PTDI_REQUEST_KERNEL_SEND)&IrpSp->Parameters;
|
|
Mdl = Irp->MdlAddress;
|
|
if (NULL == Mdl) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
SendLength = TdiRequest->SendLength;
|
|
if (SendLength > SMB_MAX_SESSION_PACKET) {
|
|
//
|
|
// Shouldn't happen, in case ......
|
|
//
|
|
ASSERT(0);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ConnectObject = SmbVerifyAndReferenceConnect(IrpSp->FileObject, SMB_REF_SEND);
|
|
if (NULL == ConnectObject) {
|
|
ASSERT(0);
|
|
return STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
SMB_ACQUIRE_SPINLOCK(ConnectObject, Irql);
|
|
if (ConnectObject->State != SMB_CONNECTED || ConnectObject->TcpContext == NULL) {
|
|
SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_SEND);
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
FileObject = ConnectObject->TcpContext->Connect.ConnectObject;
|
|
ASSERT(FileObject != NULL);
|
|
ConnectObject->PendingIRPs[SMB_PENDING_SEND] = Irp;
|
|
|
|
//
|
|
// Reference the FileObject in case that it is closed and freed.
|
|
//
|
|
ObReferenceObject(FileObject);
|
|
SMB_RELEASE_SPINLOCK(ConnectObject, Irql);
|
|
|
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|
|
|
if (Mdl->MdlFlags & MDL_NETWORK_HEADER) {
|
|
|
|
//
|
|
// Backfill mode
|
|
//
|
|
|
|
(PUCHAR)Mdl->MappedSystemVa -= SMB_SESSION_HEADER_SIZE;
|
|
Mdl->ByteOffset -= SMB_SESSION_HEADER_SIZE;
|
|
Mdl->ByteCount += SMB_SESSION_HEADER_SIZE;
|
|
SmbHdr = (PULONG)Mdl->MappedSystemVa;
|
|
*SmbHdr = htonl(SendLength);
|
|
|
|
} else {
|
|
|
|
//
|
|
// we need to attach our own header
|
|
//
|
|
|
|
pMdlNbtHdr = SmbAllocateNetBuffer(SMB_SESSION_HEADER_SIZE);
|
|
if (NULL == pMdlNbtHdr) {
|
|
ConnectObject->PendingIRPs[SMB_PENDING_SEND] = NULL;
|
|
SmbDereferenceConnect(ConnectObject, SMB_REF_SEND);
|
|
ObDereferenceObject(FileObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
ASSERT(0 == (pMdlNbtHdr->MdlFlags & MDL_NETWORK_HEADER));
|
|
SmbHdr = (PULONG)pMdlNbtHdr->MappedSystemVa;
|
|
*SmbHdr = htonl(SendLength);
|
|
pMdlNbtHdr->Next = Irp->MdlAddress;
|
|
Irp->MdlAddress = pMdlNbtHdr;
|
|
}
|
|
|
|
TdiBuildSend(
|
|
Irp,
|
|
DeviceObject,
|
|
FileObject,
|
|
(PVOID)SmbSendCompletion,
|
|
ConnectObject,
|
|
Irp->MdlAddress,
|
|
0,
|
|
SendLength + 4
|
|
);
|
|
IoMarkIrpPending(Irp);
|
|
if (ConnectObject->FastSend) {
|
|
IoSetNextIrpStackLocation(Irp);
|
|
status = ConnectObject->FastSend(Irp, IoGetCurrentIrpStackLocation(Irp));
|
|
SmbPrint(SMB_TRACE_TCP, ("SmbSend: FastSend %d bytes IoCallDriver return 0x%08lx\n", SendLength + 4, status));
|
|
} else {
|
|
status = IoCallDriver(DeviceObject, Irp);
|
|
SmbPrint(SMB_TRACE_TCP, ("SmbSend: Send %d bytes IoCallDriver return 0x%08lx\n", SendLength + 4, status));
|
|
}
|
|
ObDereferenceObject(FileObject);
|
|
|
|
return STATUS_PENDING;
|
|
}
|