/*++ 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; }