mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 21:52:59 +00:00
660 lines
22 KiB
C
660 lines
22 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/net/afd/afd/write.c
|
|
* PURPOSE: Ancillary functions driver
|
|
* PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
|
|
* UPDATE HISTORY:
|
|
* 20040708 Created
|
|
*/
|
|
|
|
#include "afd.h"
|
|
|
|
static IO_COMPLETION_ROUTINE SendComplete;
|
|
static NTSTATUS NTAPI SendComplete
|
|
( PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context ) {
|
|
NTSTATUS Status = Irp->IoStatus.Status;
|
|
PAFD_FCB FCB = (PAFD_FCB)Context;
|
|
PLIST_ENTRY NextIrpEntry;
|
|
PIRP NextIrp = NULL;
|
|
PIO_STACK_LOCATION NextIrpSp;
|
|
PAFD_SEND_INFO SendReq = NULL;
|
|
PAFD_MAPBUF Map;
|
|
UINT TotalBytesCopied = 0, TotalBytesProcessed = 0, SpaceAvail, i;
|
|
UINT SendLength, BytesCopied;
|
|
BOOLEAN HaltSendQueue;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
/*
|
|
* The Irp parameter passed in is the IRP of the stream between AFD and
|
|
* TDI driver. It's not very usefull to us. We need the IRPs of the stream
|
|
* between usermode and AFD. Those are chained from
|
|
* FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code
|
|
* below as "NextIrp" ('cause they are the next usermode IRP to be
|
|
* processed).
|
|
*/
|
|
|
|
AFD_DbgPrint(MID_TRACE,("Called, status %x, %u bytes used\n",
|
|
Irp->IoStatus.Status,
|
|
Irp->IoStatus.Information));
|
|
|
|
if( !SocketAcquireStateLock( FCB ) )
|
|
return STATUS_FILE_CLOSED;
|
|
|
|
ASSERT(FCB->SendIrp.InFlightRequest == Irp);
|
|
FCB->SendIrp.InFlightRequest = NULL;
|
|
/* Request is not in flight any longer */
|
|
|
|
if( FCB->State == SOCKET_STATE_CLOSED ) {
|
|
/* Cleanup our IRP queue because the FCB is being destroyed */
|
|
while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
|
|
NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
|
|
NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
|
|
NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
|
|
SendReq = GetLockedData(NextIrp, NextIrpSp);
|
|
NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
|
|
NextIrp->IoStatus.Information = 0;
|
|
UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
|
|
if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
|
|
(void)IoSetCancelRoutine(NextIrp, NULL);
|
|
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
|
|
}
|
|
|
|
RetryDisconnectCompletion(FCB);
|
|
|
|
SocketStateUnlock( FCB );
|
|
return STATUS_FILE_CLOSED;
|
|
}
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
/* Complete all following send IRPs with error */
|
|
|
|
while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
|
|
NextIrpEntry =
|
|
RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
|
|
NextIrp =
|
|
CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
|
|
NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
|
|
SendReq = GetLockedData(NextIrp, NextIrpSp);
|
|
|
|
UnlockBuffers( SendReq->BufferArray,
|
|
SendReq->BufferCount,
|
|
FALSE );
|
|
|
|
NextIrp->IoStatus.Status = Status;
|
|
NextIrp->IoStatus.Information = 0;
|
|
|
|
if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
|
|
(void)IoSetCancelRoutine(NextIrp, NULL);
|
|
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
|
|
}
|
|
|
|
RetryDisconnectCompletion(FCB);
|
|
|
|
SocketStateUnlock( FCB );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
RtlMoveMemory( FCB->Send.Window,
|
|
FCB->Send.Window + Irp->IoStatus.Information,
|
|
FCB->Send.BytesUsed - Irp->IoStatus.Information );
|
|
|
|
TotalBytesProcessed = 0;
|
|
SendLength = Irp->IoStatus.Information;
|
|
HaltSendQueue = FALSE;
|
|
while (!IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]) && SendLength > 0) {
|
|
NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
|
|
NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
|
|
NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
|
|
SendReq = GetLockedData(NextIrp, NextIrpSp);
|
|
Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount);
|
|
|
|
TotalBytesCopied = (ULONG_PTR)NextIrp->Tail.Overlay.DriverContext[3];
|
|
ASSERT(TotalBytesCopied != 0);
|
|
|
|
/* If we didn't get enough, keep waiting */
|
|
if (TotalBytesCopied > SendLength)
|
|
{
|
|
/* Update the bytes left to copy */
|
|
TotalBytesCopied -= SendLength;
|
|
NextIrp->Tail.Overlay.DriverContext[3] = (PVOID)TotalBytesCopied;
|
|
|
|
/* Update the state variables */
|
|
FCB->Send.BytesUsed -= SendLength;
|
|
TotalBytesProcessed += SendLength;
|
|
SendLength = 0;
|
|
|
|
/* Pend the IRP */
|
|
InsertHeadList(&FCB->PendingIrpList[FUNCTION_SEND],
|
|
&NextIrp->Tail.Overlay.ListEntry);
|
|
HaltSendQueue = TRUE;
|
|
break;
|
|
}
|
|
|
|
ASSERT(NextIrp->IoStatus.Information != 0);
|
|
|
|
NextIrp->IoStatus.Status = Irp->IoStatus.Status;
|
|
|
|
FCB->Send.BytesUsed -= TotalBytesCopied;
|
|
TotalBytesProcessed += TotalBytesCopied;
|
|
SendLength -= TotalBytesCopied;
|
|
|
|
(void)IoSetCancelRoutine(NextIrp, NULL);
|
|
|
|
UnlockBuffers( SendReq->BufferArray,
|
|
SendReq->BufferCount,
|
|
FALSE );
|
|
|
|
if (NextIrp->MdlAddress) UnlockRequest(NextIrp, NextIrpSp);
|
|
|
|
IoCompleteRequest(NextIrp, IO_NETWORK_INCREMENT);
|
|
}
|
|
|
|
ASSERT(SendLength == 0);
|
|
|
|
if ( !HaltSendQueue && !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
|
|
NextIrpEntry = FCB->PendingIrpList[FUNCTION_SEND].Flink;
|
|
NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
|
|
NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
|
|
SendReq = GetLockedData(NextIrp, NextIrpSp);
|
|
Map = (PAFD_MAPBUF)(SendReq->BufferArray + SendReq->BufferCount);
|
|
|
|
AFD_DbgPrint(MID_TRACE,("SendReq @ %p\n", SendReq));
|
|
|
|
SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
|
|
TotalBytesCopied = 0;
|
|
|
|
/* Count the total transfer size */
|
|
SendLength = 0;
|
|
for (i = 0; i < SendReq->BufferCount; i++)
|
|
{
|
|
SendLength += SendReq->BufferArray[i].len;
|
|
}
|
|
|
|
/* Make sure we've got the space */
|
|
if (SendLength > SpaceAvail)
|
|
{
|
|
/* Blocking sockets have to wait here */
|
|
if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking)))
|
|
{
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
|
|
NextIrp = NULL;
|
|
}
|
|
|
|
/* Check if we can send anything */
|
|
if (SpaceAvail == 0)
|
|
{
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
|
|
/* We should never be non-overlapped and get to this point */
|
|
ASSERT(SendReq->AfdFlags & AFD_OVERLAPPED);
|
|
|
|
NextIrp = NULL;
|
|
}
|
|
}
|
|
|
|
if (NextIrp != NULL)
|
|
{
|
|
for( i = 0; i < SendReq->BufferCount; i++ ) {
|
|
BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail);
|
|
|
|
Map[i].BufferAddress =
|
|
MmMapLockedPages( Map[i].Mdl, KernelMode );
|
|
|
|
RtlCopyMemory( FCB->Send.Window + FCB->Send.BytesUsed,
|
|
Map[i].BufferAddress,
|
|
BytesCopied );
|
|
|
|
MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
|
|
|
|
TotalBytesCopied += BytesCopied;
|
|
SpaceAvail -= BytesCopied;
|
|
FCB->Send.BytesUsed += BytesCopied;
|
|
}
|
|
|
|
NextIrp->IoStatus.Information = TotalBytesCopied;
|
|
NextIrp->Tail.Overlay.DriverContext[3] = (PVOID)NextIrp->IoStatus.Information;
|
|
}
|
|
}
|
|
|
|
if (FCB->Send.Size - FCB->Send.BytesUsed != 0 && !FCB->SendClosed &&
|
|
IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]))
|
|
{
|
|
FCB->PollState |= AFD_EVENT_SEND;
|
|
FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
|
|
PollReeval( FCB->DeviceExt, FCB->FileObject );
|
|
}
|
|
else
|
|
{
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
}
|
|
|
|
|
|
/* Some data is still waiting */
|
|
if( FCB->Send.BytesUsed )
|
|
{
|
|
Status = TdiSend( &FCB->SendIrp.InFlightRequest,
|
|
FCB->Connection.Object,
|
|
0,
|
|
FCB->Send.Window,
|
|
FCB->Send.BytesUsed,
|
|
SendComplete,
|
|
FCB );
|
|
}
|
|
else
|
|
{
|
|
/* Nothing is waiting so try to complete a pending disconnect */
|
|
RetryDisconnectCompletion(FCB);
|
|
}
|
|
|
|
SocketStateUnlock( FCB );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static IO_COMPLETION_ROUTINE PacketSocketSendComplete;
|
|
static NTSTATUS NTAPI PacketSocketSendComplete
|
|
( PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context ) {
|
|
PAFD_FCB FCB = (PAFD_FCB)Context;
|
|
PLIST_ENTRY NextIrpEntry;
|
|
PIRP NextIrp;
|
|
PAFD_SEND_INFO SendReq;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
AFD_DbgPrint(MID_TRACE,("Called, status %x, %u bytes used\n",
|
|
Irp->IoStatus.Status,
|
|
Irp->IoStatus.Information));
|
|
|
|
if( !SocketAcquireStateLock( FCB ) )
|
|
return STATUS_FILE_CLOSED;
|
|
|
|
ASSERT(FCB->SendIrp.InFlightRequest == Irp);
|
|
FCB->SendIrp.InFlightRequest = NULL;
|
|
/* Request is not in flight any longer */
|
|
|
|
if( FCB->State == SOCKET_STATE_CLOSED ) {
|
|
/* Cleanup our IRP queue because the FCB is being destroyed */
|
|
while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
|
|
NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
|
|
NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
|
|
SendReq = GetLockedData(NextIrp, IoGetCurrentIrpStackLocation(NextIrp));
|
|
NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
|
|
NextIrp->IoStatus.Information = 0;
|
|
(void)IoSetCancelRoutine(NextIrp, NULL);
|
|
UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
|
|
UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
|
|
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
|
|
}
|
|
SocketStateUnlock( FCB );
|
|
return STATUS_FILE_CLOSED;
|
|
}
|
|
|
|
ASSERT(!IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]));
|
|
|
|
/* TDI spec guarantees FIFO ordering on IRPs */
|
|
NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
|
|
NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
SendReq = GetLockedData(NextIrp, IoGetCurrentIrpStackLocation(NextIrp));
|
|
|
|
NextIrp->IoStatus.Status = Irp->IoStatus.Status;
|
|
NextIrp->IoStatus.Information = Irp->IoStatus.Information;
|
|
|
|
(void)IoSetCancelRoutine(NextIrp, NULL);
|
|
|
|
UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
|
|
|
|
UnlockRequest(NextIrp, IoGetCurrentIrpStackLocation(NextIrp));
|
|
|
|
IoCompleteRequest(NextIrp, IO_NETWORK_INCREMENT);
|
|
|
|
FCB->PollState |= AFD_EVENT_SEND;
|
|
FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
|
|
PollReeval(FCB->DeviceExt, FCB->FileObject);
|
|
|
|
SocketStateUnlock(FCB);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
PAFD_FCB FCB = FileObject->FsContext;
|
|
PAFD_SEND_INFO SendReq;
|
|
UINT TotalBytesCopied = 0, i, SpaceAvail = 0, BytesCopied, SendLength;
|
|
KPROCESSOR_MODE LockMode;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(Short);
|
|
|
|
AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB));
|
|
|
|
if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
|
|
|
|
FCB->EventSelectDisabled &= ~AFD_EVENT_SEND;
|
|
|
|
if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
|
|
{
|
|
PAFD_SEND_INFO_UDP SendReq;
|
|
PTDI_CONNECTION_INFORMATION TargetAddress;
|
|
|
|
/* Check that the socket is bound */
|
|
if( FCB->State != SOCKET_STATE_BOUND || !FCB->RemoteAddress )
|
|
{
|
|
AFD_DbgPrint(MIN_TRACE,("Invalid parameter\n"));
|
|
return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER, Irp,
|
|
0 );
|
|
}
|
|
|
|
if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) )
|
|
return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
|
|
|
|
/* Must lock buffers before handing off user data */
|
|
SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
|
|
SendReq->BufferCount,
|
|
NULL, NULL,
|
|
FALSE, FALSE, LockMode );
|
|
|
|
if( !SendReq->BufferArray ) {
|
|
return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
|
|
Irp, 0 );
|
|
}
|
|
|
|
Status = TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress );
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
|
|
Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
TdiSendDatagram(&FCB->SendIrp.InFlightRequest,
|
|
FCB->AddressFile.Object,
|
|
SendReq->BufferArray[0].buf,
|
|
SendReq->BufferArray[0].len,
|
|
TargetAddress,
|
|
PacketSocketSendComplete,
|
|
FCB);
|
|
}
|
|
|
|
ExFreePool( TargetAddress );
|
|
|
|
SocketStateUnlock(FCB);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
|
|
return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
|
|
}
|
|
}
|
|
|
|
if (FCB->PollState & AFD_EVENT_CLOSE)
|
|
{
|
|
AFD_DbgPrint(MIN_TRACE,("Connection reset by remote peer\n"));
|
|
|
|
/* This is an unexpected remote disconnect */
|
|
return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0);
|
|
}
|
|
|
|
if (FCB->PollState & AFD_EVENT_ABORT)
|
|
{
|
|
AFD_DbgPrint(MIN_TRACE,("Connection aborted\n"));
|
|
|
|
/* This is an abortive socket closure on our side */
|
|
return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0);
|
|
}
|
|
|
|
if (FCB->SendClosed)
|
|
{
|
|
AFD_DbgPrint(MIN_TRACE,("No more sends\n"));
|
|
|
|
/* This is a graceful send closure */
|
|
return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0);
|
|
}
|
|
|
|
if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) )
|
|
return UnlockAndMaybeComplete
|
|
( FCB, STATUS_NO_MEMORY, Irp, 0 );
|
|
|
|
SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
|
|
SendReq->BufferCount,
|
|
NULL, NULL,
|
|
FALSE, FALSE, LockMode );
|
|
|
|
if( !SendReq->BufferArray ) {
|
|
return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
|
|
Irp, 0 );
|
|
}
|
|
|
|
AFD_DbgPrint(MID_TRACE,("Socket state %u\n", FCB->State));
|
|
|
|
if( FCB->State != SOCKET_STATE_CONNECTED ) {
|
|
if (!(SendReq->AfdFlags & AFD_OVERLAPPED) &&
|
|
((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking))) {
|
|
AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
|
|
UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
|
|
return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 );
|
|
} else {
|
|
AFD_DbgPrint(MID_TRACE,("Queuing request\n"));
|
|
return LeaveIrpUntilLater( FCB, Irp, FUNCTION_SEND );
|
|
}
|
|
}
|
|
|
|
AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %u\n",
|
|
FCB->Send.BytesUsed));
|
|
|
|
SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
|
|
|
|
AFD_DbgPrint(MID_TRACE,("We can accept %u bytes\n",
|
|
SpaceAvail));
|
|
|
|
/* Count the total transfer size */
|
|
SendLength = 0;
|
|
for (i = 0; i < SendReq->BufferCount; i++)
|
|
{
|
|
SendLength += SendReq->BufferArray[i].len;
|
|
}
|
|
|
|
/* Make sure we've got the space */
|
|
if (SendLength > SpaceAvail)
|
|
{
|
|
/* Blocking sockets have to wait here */
|
|
if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking)))
|
|
{
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND);
|
|
}
|
|
|
|
/* Check if we can send anything */
|
|
if (SpaceAvail == 0)
|
|
{
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
|
|
/* Non-overlapped sockets will fail if we can send nothing */
|
|
if (!(SendReq->AfdFlags & AFD_OVERLAPPED))
|
|
{
|
|
UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
|
|
return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 );
|
|
}
|
|
else
|
|
{
|
|
/* Overlapped sockets just pend */
|
|
return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND);
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( i = 0; SpaceAvail > 0 && i < SendReq->BufferCount; i++ )
|
|
{
|
|
BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail);
|
|
|
|
AFD_DbgPrint(MID_TRACE,("Copying Buffer %u, %p:%u to %p\n",
|
|
i,
|
|
SendReq->BufferArray[i].buf,
|
|
BytesCopied,
|
|
FCB->Send.Window + FCB->Send.BytesUsed));
|
|
|
|
RtlCopyMemory(FCB->Send.Window + FCB->Send.BytesUsed,
|
|
SendReq->BufferArray[i].buf,
|
|
BytesCopied);
|
|
|
|
TotalBytesCopied += BytesCopied;
|
|
SpaceAvail -= BytesCopied;
|
|
FCB->Send.BytesUsed += BytesCopied;
|
|
}
|
|
|
|
Irp->IoStatus.Information = TotalBytesCopied;
|
|
|
|
if( TotalBytesCopied == 0 ) {
|
|
AFD_DbgPrint(MID_TRACE,("Empty send\n"));
|
|
UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE );
|
|
return UnlockAndMaybeComplete
|
|
( FCB, STATUS_SUCCESS, Irp, TotalBytesCopied );
|
|
}
|
|
|
|
if (SpaceAvail)
|
|
{
|
|
FCB->PollState |= AFD_EVENT_SEND;
|
|
FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
|
|
PollReeval( FCB->DeviceExt, FCB->FileObject );
|
|
}
|
|
else
|
|
{
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
}
|
|
|
|
/* We use the IRP tail for some temporary storage here */
|
|
Irp->Tail.Overlay.DriverContext[3] = (PVOID)Irp->IoStatus.Information;
|
|
|
|
Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND);
|
|
if (Status == STATUS_PENDING && !FCB->SendIrp.InFlightRequest)
|
|
{
|
|
TdiSend(&FCB->SendIrp.InFlightRequest,
|
|
FCB->Connection.Object,
|
|
0,
|
|
FCB->Send.Window,
|
|
FCB->Send.BytesUsed,
|
|
SendComplete,
|
|
FCB);
|
|
}
|
|
|
|
SocketStateUnlock(FCB);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp) {
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PTDI_CONNECTION_INFORMATION TargetAddress;
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
PAFD_FCB FCB = FileObject->FsContext;
|
|
PAFD_SEND_INFO_UDP SendReq;
|
|
KPROCESSOR_MODE LockMode;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB));
|
|
|
|
if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
|
|
|
|
FCB->EventSelectDisabled &= ~AFD_EVENT_SEND;
|
|
|
|
/* Check that the socket is bound */
|
|
if( FCB->State != SOCKET_STATE_BOUND &&
|
|
FCB->State != SOCKET_STATE_CREATED)
|
|
{
|
|
AFD_DbgPrint(MIN_TRACE,("Invalid socket state\n"));
|
|
return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
|
|
}
|
|
|
|
if (FCB->SendClosed)
|
|
{
|
|
AFD_DbgPrint(MIN_TRACE,("No more sends\n"));
|
|
return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0);
|
|
}
|
|
|
|
if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) )
|
|
return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
|
|
|
|
if (FCB->State == SOCKET_STATE_CREATED)
|
|
{
|
|
if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
|
|
FCB->LocalAddress =
|
|
TaBuildNullTransportAddress( ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
|
|
Address[0].AddressType );
|
|
|
|
if( FCB->LocalAddress ) {
|
|
Status = WarmSocketForBind( FCB, AFD_SHARE_WILDCARD );
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
FCB->State = SOCKET_STATE_BOUND;
|
|
else
|
|
return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
|
|
} else
|
|
return UnlockAndMaybeComplete
|
|
( FCB, STATUS_NO_MEMORY, Irp, 0 );
|
|
}
|
|
|
|
SendReq->BufferArray = LockBuffers( SendReq->BufferArray,
|
|
SendReq->BufferCount,
|
|
NULL, NULL,
|
|
FALSE, FALSE, LockMode );
|
|
|
|
if( !SendReq->BufferArray )
|
|
return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
|
|
Irp, 0 );
|
|
|
|
AFD_DbgPrint
|
|
(MID_TRACE,("RemoteAddress #%d Type %u\n",
|
|
((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
|
|
TAAddressCount,
|
|
((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)->
|
|
Address[0].AddressType));
|
|
|
|
Status = TdiBuildConnectionInfo( &TargetAddress,
|
|
((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress) );
|
|
|
|
/* Check the size of the Address given ... */
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
FCB->PollState &= ~AFD_EVENT_SEND;
|
|
|
|
Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
TdiSendDatagram(&FCB->SendIrp.InFlightRequest,
|
|
FCB->AddressFile.Object,
|
|
SendReq->BufferArray[0].buf,
|
|
SendReq->BufferArray[0].len,
|
|
TargetAddress,
|
|
PacketSocketSendComplete,
|
|
FCB);
|
|
}
|
|
|
|
ExFreePool(TargetAddress);
|
|
|
|
SocketStateUnlock(FCB);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE);
|
|
return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
|
|
}
|
|
}
|