summaryrefslogtreecommitdiffstats
path: root/private/ntos/afd/recvdg.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/afd/recvdg.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/afd/recvdg.c')
-rw-r--r--private/ntos/afd/recvdg.c1653
1 files changed, 1653 insertions, 0 deletions
diff --git a/private/ntos/afd/recvdg.c b/private/ntos/afd/recvdg.c
new file mode 100644
index 000000000..cc029652d
--- /dev/null
+++ b/private/ntos/afd/recvdg.c
@@ -0,0 +1,1653 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ recvdg.c
+
+Abstract:
+
+ This module contains routines for handling data receive for datagram
+ endpoints.
+
+Author:
+
+ David Treadwell (davidtr) 7-Oct-1993
+
+Revision History:
+
+--*/
+
+#include "afdp.h"
+
+NTSTATUS
+AfdSetupReceiveDatagramIrp (
+ IN PIRP Irp,
+ IN PVOID DatagramBuffer OPTIONAL,
+ IN ULONG DatagramLength,
+ IN PVOID SourceAddress,
+ IN ULONG SourceAddressLength
+ );
+
+NTSTATUS
+AfdRestartBufferReceiveDatagram (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGEAFD, AfdReceiveDatagram )
+#pragma alloc_text( PAGEAFD, AfdReceiveDatagramEventHandler )
+#pragma alloc_text( PAGEAFD, AfdSetupReceiveDatagramIrp )
+#pragma alloc_text( PAGEAFD, AfdRestartBufferReceiveDatagram )
+#pragma alloc_text( PAGEAFD, AfdCancelReceiveDatagram )
+#pragma alloc_text( PAGEAFD, AfdCleanupReceiveDatagramIrp )
+#endif
+
+//
+// Macros to make the receive datagram code more maintainable.
+//
+
+#define AfdRecvDatagramInfo DeviceIoControl
+
+#define AfdRecvAddressLength InputBufferLength
+#define AfdRecvAddressPointer Type3InputBuffer
+
+
+NTSTATUS
+AfdReceiveDatagram (
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp,
+ IN ULONG RecvFlags,
+ IN ULONG AfdFlags
+ )
+{
+ NTSTATUS status;
+ KIRQL oldIrql;
+ PAFD_ENDPOINT endpoint;
+ PLIST_ENTRY listEntry;
+ BOOLEAN peek;
+ PAFD_BUFFER afdBuffer;
+ ULONG recvFlags;
+ ULONG afdFlags;
+ ULONG recvLength;
+ PVOID addressPointer;
+ PULONG addressLength;
+ PMDL addressMdl;
+ PMDL lengthMdl;
+
+ //
+ // Set up some local variables.
+ //
+
+ endpoint = IrpSp->FileObject->FsContext;
+ ASSERT( endpoint->Type == AfdBlockTypeDatagram );
+
+ Irp->IoStatus.Information = 0;
+
+ addressMdl = NULL;
+ lengthMdl = NULL;
+
+ //
+ // If receive has been shut down or the endpoint aborted, fail.
+ //
+ // !!! Do we care if datagram endpoints get aborted?
+ //
+
+ if ( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_RECEIVE) ) {
+ status = STATUS_PIPE_DISCONNECTED;
+ goto complete;
+ }
+
+#if 0
+ if ( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) ) {
+ status = STATUS_LOCAL_DISCONNECT;
+ goto complete;
+ }
+#endif
+
+ //
+ // Do some special processing based on whether this is a receive
+ // datagram IRP, a receive IRP, or a read IRP.
+ //
+
+ if ( IrpSp->Parameters.DeviceIoControl.IoControlCode ==
+ IOCTL_AFD_RECEIVE_DATAGRAM &&
+ IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL ) {
+
+ PAFD_RECV_DATAGRAM_INFO recvInfo;
+
+ //
+ // Make sure that the endpoint is in the correct state.
+ //
+
+ if ( endpoint->State != AfdEndpointStateBound ) {
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+ }
+
+ //
+ // Grab the parameters from the input structure.
+ //
+
+ if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ sizeof(*recvInfo) ) {
+
+ try {
+
+ //
+ // Probe the input structure.
+ //
+
+ recvInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ if( Irp->RequestorMode != KernelMode ) {
+
+ ProbeForRead(
+ recvInfo,
+ sizeof(*recvInfo),
+ sizeof(ULONG)
+ );
+
+ }
+
+ //
+ // Snag the receive flags.
+ //
+
+ recvFlags = recvInfo->TdiFlags;
+ afdFlags = recvInfo->AfdFlags;
+
+ //
+ // Setup the address fields so we can return the datagram
+ // address to the user.
+ //
+
+ addressPointer = recvInfo->Address;
+ addressLength = recvInfo->AddressLength;
+
+ //
+ // Validate the WSABUF parameters.
+ //
+
+ if ( recvInfo->BufferArray != NULL &&
+ recvInfo->BufferCount > 0 ) {
+
+ //
+ // Create the MDL chain describing the WSABUF array.
+ //
+
+ status = AfdAllocateMdlChain(
+ Irp,
+ recvInfo->BufferArray,
+ recvInfo->BufferCount,
+ IoWriteAccess,
+ &recvLength
+ );
+
+ } else {
+
+ //
+ // Zero-length input buffer. This is OK for datagrams.
+ //
+
+ ASSERT( Irp->MdlAddress == NULL );
+ status = STATUS_SUCCESS;
+
+ }
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ //
+ // Exception accessing input structure.
+ //
+
+ status = GetExceptionCode();
+
+ }
+
+ } else {
+
+ //
+ // Invalid input buffer length.
+ //
+
+ status = STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // If only one of addressPointer or addressLength are NULL, then
+ // fail the request.
+ //
+
+ if( (addressPointer == NULL) ^ (addressLength == NULL) ) {
+
+ status = STATUS_INVALID_PARAMETER;
+ goto complete;
+
+ }
+
+ if( !NT_SUCCESS(status) ) {
+
+ goto complete;
+
+ }
+
+ //
+ // If the user wants the source address from the receive datagram,
+ // then create MDLs for the address & address length, then probe
+ // and lock the MDLs.
+ //
+
+ if( addressPointer != NULL ) {
+
+ ASSERT( addressLength != NULL );
+
+ //
+ // Setup so we know how to cleanup after the try/except block.
+ //
+
+ status = STATUS_SUCCESS;
+
+ try {
+
+ //
+ // Bomb off if the user is trying to do something stupid, like
+ // specify a zero-length address, or one that's unreasonably
+ // huge. Here, we (arbitrarily) define "unreasonably huge" as
+ // anything 64K or greater.
+ //
+
+ if( *addressLength == 0 ||
+ *addressLength >= 65536 ) {
+
+ ExRaiseStatus( STATUS_INVALID_PARAMETER );
+
+ }
+
+ //
+ // Create a MDL describing the address buffer, then probe
+ // it for write access.
+ //
+
+ addressMdl = IoAllocateMdl(
+ addressPointer, // VirtualAddress
+ *addressLength, // Length
+ FALSE, // SecondaryBuffer
+ TRUE, // ChargeQuota
+ NULL // Irp
+ );
+
+ if( addressMdl == NULL ) {
+
+ ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
+
+ }
+
+ MmProbeAndLockPages(
+ addressMdl, // MemoryDescriptorList
+ Irp->RequestorMode, // AccessMode
+ IoWriteAccess // Operation
+ );
+
+ //
+ // Create a MDL describing the length buffer, then probe it
+ // for write access.
+ //
+
+ lengthMdl = IoAllocateMdl(
+ addressLength, // VirtualAddress
+ sizeof(*addressLength), // Length
+ FALSE, // SecondaryBuffer
+ TRUE, // ChargeQuota
+ NULL // Irp
+ );
+
+ if( lengthMdl == NULL ) {
+
+ ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
+
+ }
+
+ MmProbeAndLockPages(
+ lengthMdl, // MemoryDescriptorList
+ Irp->RequestorMode, // AccessMode
+ IoWriteAccess // Operation
+ );
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+
+ status = GetExceptionCode();
+
+ }
+
+ if( !NT_SUCCESS(status) ) {
+
+ goto complete;
+
+ }
+
+ ASSERT( addressMdl != NULL );
+ ASSERT( lengthMdl != NULL );
+
+ } else {
+
+ ASSERT( addressMdl == NULL );
+ ASSERT( lengthMdl == NULL );
+
+ }
+
+ //
+ // Validate the receive flags.
+ //
+
+ if( ( recvFlags & TDI_RECEIVE_EITHER ) != TDI_RECEIVE_NORMAL ) {
+ status = STATUS_NOT_SUPPORTED;
+ goto complete;
+ }
+
+ peek = (BOOLEAN)( (recvFlags & TDI_RECEIVE_PEEK) != 0 );
+
+ } else {
+
+ ASSERT( (Irp->Flags & IRP_INPUT_OPERATION) == 0 );
+
+ if ( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL ) {
+
+ //
+ // Grab the input parameters from the IRP.
+ //
+
+ ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode ==
+ IOCTL_AFD_RECEIVE );
+
+ recvFlags = RecvFlags;
+ afdFlags = AfdFlags;
+
+ //
+ // It is illegal to attempt to receive expedited data on a
+ // datagram endpoint.
+ //
+
+ if ( (recvFlags & TDI_RECEIVE_EXPEDITED) != 0 ) {
+ status = STATUS_NOT_SUPPORTED;
+ goto complete;
+ }
+
+ ASSERT( ( recvFlags & TDI_RECEIVE_EITHER ) == TDI_RECEIVE_NORMAL );
+
+ peek = (BOOLEAN)( (recvFlags & TDI_RECEIVE_PEEK) != 0 );
+
+ } else {
+
+ //
+ // This must be a read IRP. There are no special options
+ // for a read IRP.
+ //
+
+ ASSERT( IrpSp->MajorFunction == IRP_MJ_READ );
+
+ recvFlags = TDI_RECEIVE_NORMAL;
+ afdFlags = AFD_OVERLAPPED;
+ peek = FALSE;
+
+ }
+
+ ASSERT( addressMdl == NULL );
+ ASSERT( lengthMdl == NULL );
+
+ }
+
+ //
+ // Save the address & length MDLs in the current IRP stack location.
+ // These will be used later in SetupReceiveDatagramIrp(). Note that
+ // they should either both be NULL or both be non-NULL.
+ //
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
+
+ ASSERT( !( ( addressMdl == NULL ) ^ ( lengthMdl == NULL ) ) );
+
+ IrpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressPointer =
+ (PVOID)addressMdl;
+ IrpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressLength =
+ (ULONG)lengthMdl;
+
+ //
+ // Determine whether there are any datagrams already bufferred on
+ // this endpoint. If there is a bufferred datagram, we'll use it to
+ // complete the IRP.
+ //
+
+ if ( endpoint->BufferredDatagramCount != 0 ) {
+
+ KIRQL saveIrql;
+
+ //
+ // There is at least one datagram bufferred on the endpoint.
+ // Use it for this receive.
+ //
+
+ ASSERT( !IsListEmpty( &endpoint->ReceiveDatagramBufferListHead ) );
+
+ listEntry = endpoint->ReceiveDatagramBufferListHead.Flink;
+ afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
+
+ //
+ // Prepare the user's IRP for completion.
+ //
+
+ status = AfdSetupReceiveDatagramIrp (
+ Irp,
+ afdBuffer->Buffer,
+ afdBuffer->DataLength,
+ afdBuffer->SourceAddress,
+ afdBuffer->SourceAddressLength
+ );
+
+ //
+ // Release the cancel spin lock, since we don't need it.
+ // However, be careful about the IRQLs because we're releasing
+ // locks in a different order than we acquired them.
+ //
+
+ saveIrql = Irp->CancelIrql;
+ IoReleaseCancelSpinLock( oldIrql );
+ oldIrql = saveIrql;
+
+ //
+ // If this wasn't a peek IRP, remove the buffer from the endpoint's
+ // list of bufferred datagrams.
+ //
+
+ if ( !peek ) {
+
+ RemoveHeadList( &endpoint->ReceiveDatagramBufferListHead );
+
+ //
+ // Update the counts of bytes and datagrams on the endpoint.
+ //
+
+ endpoint->BufferredDatagramCount--;
+ endpoint->BufferredDatagramBytes -= afdBuffer->DataLength;
+ endpoint->EventsActive &= ~AFD_POLL_RECEIVE;
+
+ IF_DEBUG(EVENT_SELECT) {
+ KdPrint((
+ "AfdReceiveDatagram: Endp %08lX, Active %08lX\n",
+ endpoint,
+ endpoint->EventsActive
+ ));
+ }
+
+ if( endpoint->BufferredDatagramCount > 0 ) {
+
+ AfdIndicateEventSelectEvent(
+ endpoint,
+ AFD_POLL_RECEIVE_BIT,
+ STATUS_SUCCESS
+ );
+
+ }
+ }
+
+ //
+ // We've set up all return information. Clean up and complete
+ // the IRP.
+ //
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+
+ if ( !peek ) {
+ AfdReturnBuffer( afdBuffer );
+ }
+
+ IoCompleteRequest( Irp, 0 );
+
+ return status;
+ }
+
+ //
+ // There were no datagrams bufferred on the endpoint. If this is a
+ // nonblocking endpoint and the request was a normal receive (as
+ // opposed to a read IRP), fail the request. We don't fail reads
+ // under the asumption that if the application is doing reads they
+ // don't want nonblocking behavior.
+ //
+
+ if ( endpoint->NonBlocking && !ARE_DATAGRAMS_ON_ENDPOINT( endpoint ) &&
+ !( afdFlags & AFD_OVERLAPPED ) ) {
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ status = STATUS_DEVICE_NOT_READY;
+ goto complete;
+ }
+
+ //
+ // We'll have to pend the IRP. Place the IRP on the appropriate IRP
+ // list in the endpoint.
+ //
+
+ if ( peek ) {
+ InsertTailList(
+ &endpoint->PeekDatagramIrpListHead,
+ &Irp->Tail.Overlay.ListEntry
+ );
+ } else {
+ InsertTailList(
+ &endpoint->ReceiveDatagramIrpListHead,
+ &Irp->Tail.Overlay.ListEntry
+ );
+ }
+
+ IoMarkIrpPending( Irp );
+
+ //
+ // Set up the cancellation routine in the IRP. If the IRP has already
+ // been cancelled, just call the cancellation routine here.
+ //
+
+ if ( Irp->Cancel ) {
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ AfdCancelReceiveDatagram( IrpSp->DeviceObject, Irp );
+ status = STATUS_CANCELLED;
+ goto complete;
+ }
+
+ IoSetCancelRoutine( Irp, AfdCancelReceiveDatagram );
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ return STATUS_PENDING;
+
+complete:
+
+ ASSERT( !NT_SUCCESS(status) );
+
+ if( addressMdl != NULL ) {
+ if( (addressMdl->MdlFlags & MDL_PAGES_LOCKED) != 0 ) {
+ MmUnlockPages( addressMdl );
+ }
+ IoFreeMdl( addressMdl );
+ }
+
+ if( lengthMdl != NULL ) {
+ if( (lengthMdl->MdlFlags & MDL_PAGES_LOCKED) != 0 ) {
+ MmUnlockPages( lengthMdl );
+ }
+ IoFreeMdl( lengthMdl );
+ }
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest( Irp, 0 );
+
+ return status;
+
+} // AfdReceiveDatagram
+
+
+NTSTATUS
+AfdReceiveDatagramEventHandler (
+ IN PVOID TdiEventContext,
+ IN int SourceAddressLength,
+ IN PVOID SourceAddress,
+ IN int OptionsLength,
+ IN PVOID Options,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *BytesTaken,
+ IN PVOID Tsdu,
+ OUT PIRP *IoRequestPacket
+ )
+
+/*++
+
+Routine Description:
+
+ Handles receive datagram events for nonbufferring transports.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ PAFD_ENDPOINT endpoint;
+ PLIST_ENTRY listEntry;
+ PAFD_BUFFER afdBuffer;
+ PIRP irp;
+ ULONG requiredAfdBufferSize;
+ BOOLEAN userIrp;
+
+ endpoint = TdiEventContext;
+ ASSERT( endpoint != NULL );
+ ASSERT( endpoint->Type == AfdBlockTypeDatagram );
+
+#if AFD_PERF_DBG
+ if ( BytesAvailable == BytesIndicated ) {
+ AfdFullReceiveDatagramIndications++;
+ } else {
+ AfdPartialReceiveDatagramIndications++;
+ }
+#endif
+
+ //
+ // If this endpoint is connected and the datagram is for a different
+ // address than the one the endpoint is connected to, drop the
+ // datagram. Also, if we're in the process of connecting the
+ // endpoint to a remote address, the MaximumDatagramCount field will
+ // be 0, in which case we shoul drop the datagram.
+ //
+
+ IoAcquireCancelSpinLock( &cancelIrql );
+ AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
+
+ if ( (endpoint->State == AfdEndpointStateConnected &&
+ !AfdAreTransportAddressesEqual(
+ endpoint->Common.Datagram.RemoteAddress,
+ endpoint->Common.Datagram.RemoteAddressLength,
+ SourceAddress,
+ SourceAddressLength,
+ TRUE )) ||
+ (endpoint->Common.Datagram.MaxBufferredReceiveCount == 0) ) {
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( cancelIrql );
+
+ *BytesTaken = BytesAvailable;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Check whether there are any IRPs waiting on the endpoint. If
+ // there is such an IRP, use it to receive the datagram.
+ //
+
+ if ( !IsListEmpty( &endpoint->ReceiveDatagramIrpListHead ) ) {
+
+ ASSERT( *BytesTaken == 0 );
+ ASSERT( endpoint->BufferredDatagramCount == 0 );
+ ASSERT( endpoint->BufferredDatagramBytes == 0 );
+
+ listEntry = RemoveHeadList( &endpoint->ReceiveDatagramIrpListHead );
+
+ //
+ // Get a pointer to the IRP and reset the cancel routine in
+ // the IRP. The IRP is no longer cancellable.
+ //
+
+ irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
+ IoSetCancelRoutine( irp, NULL );
+
+ //
+ // If the entire datagram is being indicated to us here, just
+ // copy the information to the MDL in the IRP and return.
+ //
+ // Note that we'll also take the entire datagram if the user
+ // has pended a zero-byte datagram receive (detectable as a
+ // NULL Irp->MdlAddress). We'll eat the datagram and fall
+ // through to AfdSetupReceiveDatagramIrp(), which will store
+ // an error status in the IRP since the user's buffer is
+ // insufficient to hold the datagram.
+ //
+
+ if( BytesIndicated == BytesAvailable ||
+ irp->MdlAddress == NULL ) {
+
+ //
+ // Set BytesTaken to indicate that we've taken all the
+ // data. We do it here because we already have
+ // BytesAvailable in a register, which probably won't
+ // be true after making function calls.
+ //
+
+ *BytesTaken = BytesAvailable;
+
+ //
+ // Copy the datagram and source address to the IRP. This
+ // prepares the IRP to be completed.
+ //
+ // !!! do we need a special version of this routine to
+ // handle special RtlCopyMemory, like for
+ // TdiCopyLookaheadBuffer?
+ //
+
+ (VOID)AfdSetupReceiveDatagramIrp (
+ irp,
+ Tsdu,
+ BytesAvailable,
+ SourceAddress,
+ SourceAddressLength
+ );
+
+ //
+ // The IRP is off the endpoint's list and is no longer
+ // cancellable. We can release the locks we hold.
+ //
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( cancelIrql );
+
+ //
+ // Complete the IRP. We've already set BytesTaken
+ // to tell the provider that we have taken all the data.
+ //
+
+ IoCompleteRequest( irp, AfdPriorityBoost );
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Some of the datagram was not indicated, so remember that we
+ // want to pass back this IRP to the TDI provider. Passing back
+ // this IRP directly is good because it avoids having to copy
+ // the data from one of our buffers into the user's buffer.
+ //
+
+ userIrp = TRUE;
+ requiredAfdBufferSize = 0;
+
+ } else {
+
+ userIrp = FALSE;
+ requiredAfdBufferSize = BytesAvailable;
+ }
+
+ //
+ // There were no IRPs available to take the datagram, so we'll have
+ // to buffer it. First make sure that we're not over the limit
+ // of bufferring that we can do. If we're over the limit, toss
+ // this datagram.
+ //
+
+ if ( endpoint->BufferredDatagramCount >=
+ endpoint->Common.Datagram.MaxBufferredReceiveCount ||
+ endpoint->BufferredDatagramBytes >=
+ endpoint->Common.Datagram.MaxBufferredReceiveBytes ) {
+
+ //
+ // If circular queueing is not enabled, then just drop the
+ // datagram on the floor.
+ //
+
+
+ if( !endpoint->Common.Datagram.CircularQueueing ) {
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( cancelIrql );
+ *BytesTaken = BytesAvailable;
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Circular queueing is enabled, so drop packets at the head of
+ // the receive queue until we're below the receive limit.
+ //
+
+ while( endpoint->BufferredDatagramCount >=
+ endpoint->Common.Datagram.MaxBufferredReceiveCount ||
+ endpoint->BufferredDatagramBytes >=
+ endpoint->Common.Datagram.MaxBufferredReceiveBytes ) {
+
+ listEntry = RemoveHeadList( &endpoint->ReceiveDatagramBufferListHead );
+ afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
+
+ endpoint->BufferredDatagramCount--;
+ endpoint->BufferredDatagramBytes -= afdBuffer->DataLength;
+
+ AfdReturnBuffer( afdBuffer );
+
+ }
+
+ //
+ // Proceed to accept the incoming packet.
+ //
+
+ }
+
+ //
+ // We're able to buffer the datagram. Now acquire a buffer of
+ // appropriate size.
+ //
+
+ afdBuffer = AfdGetBuffer( requiredAfdBufferSize, SourceAddressLength );
+
+ if ( afdBuffer == NULL ) {
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( cancelIrql );
+ *BytesTaken = BytesAvailable;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If the entire datagram is being indicated to us, just copy it
+ // here.
+ //
+
+ if ( BytesIndicated == BytesAvailable ) {
+
+ ASSERT( !userIrp );
+
+ //
+ // If there is a peek IRP on the endpoint, remove it from the
+ // list and prepare to complete it. We can't complete it now
+ // because we hold a spin lock.
+ //
+
+ if ( !IsListEmpty( &endpoint->PeekDatagramIrpListHead ) ) {
+
+ //
+ // Remove the first peek IRP from the list and get a pointer
+ // to it.
+ //
+
+ listEntry = RemoveHeadList( &endpoint->PeekDatagramIrpListHead );
+ irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
+
+ //
+ // Reset the cancel routine in the IRP. The IRP is no
+ // longer cancellable, since we're about to complete it.
+ //
+
+ IoSetCancelRoutine( irp, NULL );
+
+ //
+ // Copy the datagram and source address to the IRP. This
+ // prepares the IRP to be completed.
+ //
+
+ (VOID)AfdSetupReceiveDatagramIrp (
+ irp,
+ Tsdu,
+ BytesAvailable,
+ SourceAddress,
+ SourceAddressLength
+ );
+
+ } else {
+
+ irp = NULL;
+ }
+
+ //
+ // We don't need the cancel spin lock any more, so we can
+ // release it. However, since we acquired the cancel spin lock
+ // after the endpoint spin lock and we still need the endpoint
+ // spin lock, be careful to switch the IRQLs.
+ //
+
+ IoReleaseCancelSpinLock( oldIrql );
+ oldIrql = cancelIrql;
+
+ //
+ // Use the special function to copy the data instead of
+ // RtlCopyMemory in case the data is coming from a special place
+ // (DMA, etc.) which cannot work with RtlCopyMemory.
+ //
+
+ TdiCopyLookaheadData(
+ afdBuffer->Buffer,
+ Tsdu,
+ BytesAvailable,
+ ReceiveDatagramFlags
+ );
+
+ //
+ // Store the data length and set the offset to 0.
+ //
+
+ afdBuffer->DataLength = BytesAvailable;
+ ASSERT( afdBuffer->DataOffset == 0 );
+
+ //
+ // Store the address of the sender of the datagram.
+ //
+
+ RtlCopyMemory(
+ afdBuffer->SourceAddress,
+ SourceAddress,
+ SourceAddressLength
+ );
+
+ afdBuffer->SourceAddressLength = SourceAddressLength;
+
+ //
+ // Place the buffer on this endpoint's list of bufferred datagrams
+ // and update the counts of datagrams and datagram bytes on the
+ // endpoint.
+ //
+
+ InsertTailList(
+ &endpoint->ReceiveDatagramBufferListHead,
+ &afdBuffer->BufferListEntry
+ );
+
+ endpoint->BufferredDatagramCount++;
+ endpoint->BufferredDatagramBytes += BytesAvailable;
+
+ //
+ // All done. Release the lock and tell the provider that we
+ // took all the data.
+ //
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+
+ //
+ // Indicate that it is possible to receive on the endpoint now.
+ //
+
+ AfdIndicatePollEvent(
+ endpoint,
+ AFD_POLL_RECEIVE_BIT,
+ STATUS_SUCCESS
+ );
+
+ //
+ // If there was a peek IRP on the endpoint, complete it now.
+ //
+
+ if ( irp != NULL ) {
+ IoCompleteRequest( irp, AfdPriorityBoost );
+ }
+
+ *BytesTaken = BytesAvailable;
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // We'll have to format up an IRP and give it to the provider to
+ // handle. We don't need any locks to do this--the restart routine
+ // will check whether new receive datagram IRPs were pended on the
+ // endpoint.
+ //
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( cancelIrql );
+
+ //
+ // Use the IRP in the AFD buffer if appropriate. If userIrp is
+ // TRUE, then the local variable irp will already point to the
+ // user's IRP which we'll use for this IO.
+ //
+
+ if ( !userIrp ) {
+ irp = afdBuffer->Irp;
+ ASSERT( afdBuffer->Mdl == irp->MdlAddress );
+ }
+
+ //
+ // Tell the TDI provider where to put the source address.
+ //
+
+ afdBuffer->TdiOutputInfo.RemoteAddressLength = afdBuffer->AllocatedAddressLength;
+ afdBuffer->TdiOutputInfo.RemoteAddress = afdBuffer->SourceAddress;
+
+ //
+ // We need to remember the endpoint in the AFD buffer because we'll
+ // need to access it in the completion routine.
+ //
+
+ afdBuffer->Context = endpoint;
+
+ //
+ // Finish building the receive datagram request.
+ //
+
+ TdiBuildReceiveDatagram(
+ irp,
+ endpoint->AddressDeviceObject,
+ endpoint->AddressFileObject,
+ AfdRestartBufferReceiveDatagram,
+ afdBuffer,
+ irp->MdlAddress,
+ BytesAvailable,
+ &afdBuffer->TdiInputInfo,
+ &afdBuffer->TdiOutputInfo,
+ 0
+ );
+
+ //
+ // Make the next stack location current. Normally IoCallDriver would
+ // do this, but since we're bypassing that, we do it directly.
+ //
+
+ IoSetNextIrpStackLocation( irp );
+
+ *IoRequestPacket = irp;
+ *BytesTaken = 0;
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+} // AfdReceiveDatagramEventHandler
+
+
+NTSTATUS
+AfdRestartBufferReceiveDatagram (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Handles completion of bufferred datagram receives that were started
+ in the datagram indication handler.
+
+Arguments:
+
+ DeviceObject - not used.
+
+ Irp - the IRP that is completing.
+
+ Context - the endpoint which received the datagram.
+
+Return Value:
+
+ NTSTATUS - if this is our IRP, then always
+ STATUS_MORE_PROCESSING_REQUIRED to indicate to the IO system that we
+ own the IRP and the IO system should stop processing the it.
+
+ If this is a user's IRP, then STATUS_SUCCESS to indicate that
+ IO completion should continue.
+
+--*/
+
+{
+ PAFD_ENDPOINT endpoint;
+ KIRQL oldIrql;
+ KIRQL cancelIrql;
+ PAFD_BUFFER afdBuffer;
+ PIRP pendedIrp;
+ PLIST_ENTRY listEntry;
+
+ ASSERT( NT_SUCCESS(Irp->IoStatus.Status) );
+
+ afdBuffer = Context;
+
+ endpoint = afdBuffer->Context;
+ ASSERT( endpoint->Type == AfdBlockTypeDatagram );
+
+ //
+ // Remember the length of the received datagram and the length
+ // of the source address.
+ //
+
+ afdBuffer->DataLength = Irp->IoStatus.Information;
+ afdBuffer->SourceAddressLength = afdBuffer->TdiOutputInfo.RemoteAddressLength;
+
+ //
+ // Zero the fields of the TDI info structures in the AFD buffer
+ // that we used. They must be zero when we return the buffer.
+ //
+
+ afdBuffer->TdiOutputInfo.RemoteAddressLength = 0;
+ afdBuffer->TdiOutputInfo.RemoteAddress = NULL;
+
+ //
+ // If the IRP being completed is actually a user's IRP, set it up
+ // for completion and allow IO completion to finish.
+ //
+
+ if ( Irp != afdBuffer->Irp ) {
+
+ //
+ // Set up the IRP for completion.
+ //
+
+ IoAcquireCancelSpinLock( &cancelIrql );
+
+ (VOID)AfdSetupReceiveDatagramIrp (
+ Irp,
+ NULL,
+ Irp->IoStatus.Information,
+ afdBuffer->SourceAddress,
+ afdBuffer->SourceAddressLength
+ );
+
+ IoReleaseCancelSpinLock( cancelIrql );
+
+ //
+ // Free the AFD buffer we've been using to track this request.
+ //
+
+ AfdReturnBuffer( afdBuffer );
+
+ //
+ // If pending has be returned for this irp then mark the current
+ // stack as pending.
+ //
+
+ if ( Irp->PendingReturned ) {
+ IoMarkIrpPending(Irp);
+ }
+
+ //
+ // Tell the IO system that it is OK to continue with IO
+ // completion.
+ //
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If the IO failed, then just return the AFD buffer to our buffer
+ // pool.
+ //
+
+ if ( !NT_SUCCESS(Irp->IoStatus.Status) ) {
+ AfdReturnBuffer( afdBuffer );
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ //
+ // If there are any pended IRPs on the endpoint, complete as
+ // appropriate with the new information.
+ //
+
+ IoAcquireCancelSpinLock( &cancelIrql );
+ AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
+
+ if ( !IsListEmpty( &endpoint->ReceiveDatagramIrpListHead ) ) {
+
+ //
+ // There was a pended receive datagram IRP. Remove it from the
+ // head of the list.
+ //
+
+ listEntry = RemoveHeadList( &endpoint->ReceiveDatagramIrpListHead );
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+
+ //
+ // Get a pointer to the IRP and reset the cancel routine in
+ // the IRP. The IRP is no longer cancellable.
+ //
+
+ pendedIrp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
+
+ IoSetCancelRoutine( pendedIrp, NULL );
+
+ //
+ // Set up the user's IRP for completion.
+ //
+
+ (VOID)AfdSetupReceiveDatagramIrp (
+ pendedIrp,
+ afdBuffer->Buffer,
+ afdBuffer->DataLength,
+ afdBuffer->SourceAddress,
+ afdBuffer->SourceAddressLength
+ );
+
+ IoReleaseCancelSpinLock( cancelIrql );
+
+ //
+ // Complete the user's IRP, free the AFD buffer we used for
+ // the request, and tell the IO system that we're done
+ // processing this request.
+ //
+
+ IoCompleteRequest( pendedIrp, AfdPriorityBoost );
+
+ AfdReturnBuffer( afdBuffer );
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ //
+ // If there are any pended peek IRPs on the endpoint, complete
+ // one with this datagram.
+ //
+
+ if ( !IsListEmpty( &endpoint->PeekDatagramIrpListHead ) ) {
+
+ //
+ // There was a pended peek receive datagram IRP. Remove it from
+ // the head of the list.
+ //
+
+ listEntry = RemoveHeadList( &endpoint->PeekDatagramIrpListHead );
+
+ //
+ // Get a pointer to the IRP and reset the cancel routine in
+ // the IRP. The IRP is no longer cancellable.
+ //
+
+ pendedIrp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
+
+ IoSetCancelRoutine( pendedIrp, NULL );
+
+ //
+ // Set up the user's IRP for completion.
+ //
+
+ (VOID)AfdSetupReceiveDatagramIrp (
+ pendedIrp,
+ afdBuffer->Buffer,
+ afdBuffer->DataLength,
+ afdBuffer->SourceAddress,
+ afdBuffer->SourceAddressLength
+ );
+
+ //
+ // Don't complete the pended peek IRP yet, since we still hold
+ // locks. Wait until it is safe to release the locks.
+ //
+
+ } else {
+
+ pendedIrp = NULL;
+ }
+
+ //
+ // Place the datagram at the end of the endpoint's list of bufferred
+ // datagrams, and update counts of datagrams on the endpoint.
+ //
+
+ InsertTailList(
+ &endpoint->ReceiveDatagramBufferListHead,
+ &afdBuffer->BufferListEntry
+ );
+
+ endpoint->BufferredDatagramCount++;
+ endpoint->BufferredDatagramBytes += afdBuffer->DataLength;
+
+ //
+ // Release locks and indicate that there are bufferred datagrams
+ // on the endpoint.
+ //
+
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+ IoReleaseCancelSpinLock( cancelIrql );
+
+ AfdIndicatePollEvent(
+ endpoint,
+ AFD_POLL_RECEIVE_BIT,
+ STATUS_SUCCESS
+ );
+
+ //
+ // If there was a pended peek IRP to complete, complete it now.
+ //
+
+ if ( pendedIrp != NULL ) {
+ IoCompleteRequest( pendedIrp, 2 );
+ }
+
+ //
+ // Tell the IO system to stop processing this IRP, since we now own
+ // it as part of the AFD buffer.
+ //
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+} // AfdRestartBufferReceiveDatagram
+
+
+VOID
+AfdCancelReceiveDatagram (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Cancels a receive datagram IRP that is pended in AFD.
+
+Arguments:
+
+ DeviceObject - not used.
+
+ Irp - the IRP to cancel.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ PAFD_ENDPOINT endpoint;
+ KIRQL oldIrql;
+ PMDL mdl;
+
+ //
+ // Get the endpoint pointer from our IRP stack location.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+ endpoint = irpSp->FileObject->FsContext;
+
+ ASSERT( endpoint->Type == AfdBlockTypeDatagram );
+
+ //
+ // Remove the IRP from the endpoint's IRP list, synchronizing with
+ // the endpoint lock which protects the lists. Note that the
+ // IRP *must* be on one of the endpoint's lists if we are getting
+ // called here--anybody that removes the IRP from the list must
+ // do so while holding the cancel spin lock and reset the cancel
+ // routine to NULL before releasing the cancel spin lock.
+ //
+
+ AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+ AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
+
+ //
+ // Reset the cancel routine in the IRP.
+ //
+
+ IoSetCancelRoutine( Irp, NULL );
+
+ //
+ // Free any MDL chains attached to the IRP stack location.
+ //
+
+ AfdCleanupReceiveDatagramIrp( Irp );
+
+ //
+ // Release the cancel spin lock and complete the IRP with a
+ // cancellation status code.
+ //
+
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+
+ IoCompleteRequest( Irp, AfdPriorityBoost );
+
+ return;
+
+} // AfdCancelReceiveDatagram
+
+
+VOID
+AfdCleanupReceiveDatagramIrp(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Performs any cleanup specific to receive datagram IRPs.
+
+Arguments:
+
+ Irp - the IRP to cleanup.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This routine may be called at raised IRQL from AfdCompleteIrpList().
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpSp;
+ PMDL mdl;
+
+ //
+ // Get the endpoint pointer from our IRP stack location.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Free any MDL chains attached to the IRP stack location.
+ //
+
+ mdl = (PMDL)irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressPointer;
+
+ if( mdl != NULL ) {
+ irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressPointer = NULL;
+ MmUnlockPages( mdl );
+ IoFreeMdl( mdl );
+ }
+
+ mdl = (PMDL)irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressLength;
+
+ if( mdl != NULL ) {
+ irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressLength = 0;
+ MmUnlockPages( mdl );
+ IoFreeMdl( mdl );
+ }
+
+} // AfdCleanupReceiveDatagramIrp
+
+
+NTSTATUS
+AfdSetupReceiveDatagramIrp (
+ IN PIRP Irp,
+ IN PVOID DatagramBuffer OPTIONAL,
+ IN ULONG DatagramLength,
+ IN PVOID SourceAddress,
+ IN ULONG SourceAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ Copies the datagram to the MDL in the IRP and the datagram sender's
+ address to the appropriate place in the system buffer.
+
+ NOTE: This function MUST be called with the I/O cancel spinlock held!
+
+Arguments:
+
+ Irp - the IRP to prepare for completion.
+
+ DatagramBuffer - datagram to copy into the IRP. If NULL, then
+ there is no need to copy the datagram to the IRP's MDL, the
+ datagram has already been copied there.
+
+ DatagramLength - the length of the datagram to copy.
+
+ SourceAddress - address of the sender of the datagram.
+
+ SourceAddressLength - length of the source address.
+
+Return Value:
+
+ NTSTATUS - The status code placed into the IRP.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ ULONG bytesCopied;
+ PMDL addressPointer;
+ PMDL addressLength;
+ PTRANSPORT_ADDRESS tdiAddress;
+ ULONG addressBytesCopied;
+ NTSTATUS status2;
+ KIRQL cancelIrql;
+
+ ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
+
+ //
+ // If necessary, copy the datagram in the buffer to the MDL in the
+ // user's IRP. If there is no MDL in the buffer, then fail if the
+ // datagram is larger than 0 bytes.
+ //
+
+ if ( ARGUMENT_PRESENT( DatagramBuffer ) ) {
+
+ if ( Irp->MdlAddress == NULL ) {
+
+ if ( DatagramLength != 0 ) {
+ status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ status = STATUS_SUCCESS;
+ }
+
+ bytesCopied = 0;
+
+ } else {
+
+ status = TdiCopyBufferToMdl(
+ DatagramBuffer,
+ 0,
+ DatagramLength,
+ Irp->MdlAddress,
+ 0,
+ &bytesCopied
+ );
+ }
+
+ } else {
+
+ //
+ // The information was already copied to the MDL chain in the
+ // IRP. Just remember the IO status block so we can do the
+ // right thing with it later.
+ //
+
+ status = Irp->IoStatus.Status;
+ bytesCopied = Irp->IoStatus.Information;
+ }
+
+ //
+ // To determine how to complete setting up the IRP for completion,
+ // figure out whether this IRP was for regular datagram information,
+ // in which case we need to return an address, or for data only, in
+ // which case we will not return the source address. NtReadFile()
+ // and recv() on connected datagram sockets will result in the
+ // latter type of IRP.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ addressPointer =
+ (PMDL)irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressPointer;
+ addressLength =
+ (PMDL)irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressLength;
+
+ irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressPointer = NULL;
+ irpSp->Parameters.AfdRecvDatagramInfo.AfdRecvAddressLength = 0;
+
+ if( addressPointer != NULL ) {
+
+ ASSERT( irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_AFD_RECEIVE_DATAGRAM );
+
+ ASSERT( addressPointer->Next == NULL );
+ ASSERT( ( addressPointer->MdlFlags & MDL_PAGES_LOCKED ) != 0 );
+ ASSERT( addressPointer->Size > 0 );
+
+ ASSERT( addressLength != NULL );
+ ASSERT( addressLength->Next == NULL );
+ ASSERT( ( addressLength->MdlFlags & MDL_PAGES_LOCKED ) != 0 );
+ ASSERT( addressLength->Size > 0 );
+
+ //
+ // Extract the real SOCKADDR structure from the TDI address.
+ // This duplicates MSAFD.DLL's SockBuildSockaddr() function.
+ //
+
+ tdiAddress = SourceAddress;
+
+ ASSERT( sizeof(tdiAddress->Address[0].AddressType) == sizeof(u_short) );
+ ASSERT( FIELD_OFFSET( TA_ADDRESS, AddressLength ) == 0 );
+ ASSERT( FIELD_OFFSET( TA_ADDRESS, AddressType ) == sizeof(USHORT) );
+ ASSERT( FIELD_OFFSET( TRANSPORT_ADDRESS, Address[0] ) == sizeof(int) );
+ ASSERT( SourceAddressLength >=
+ (tdiAddress->Address[0].AddressLength + sizeof(u_short)) );
+
+ SourceAddressLength = tdiAddress->Address[0].AddressLength +
+ sizeof(u_short); // sa_family
+ SourceAddress = &tdiAddress->Address[0].AddressType;
+
+ //
+ // Copy the address to the user's buffer, then unlock and
+ // free the MDL describing the user's buffer.
+ //
+
+ status2 = TdiCopyBufferToMdl(
+ SourceAddress,
+ 0,
+ SourceAddressLength,
+ addressPointer,
+ 0,
+ &addressBytesCopied
+ );
+
+ MmUnlockPages( addressPointer );
+ IoFreeMdl( addressPointer );
+
+ //
+ // If the above TdiCopyBufferToMdl was successful, then
+ // copy the address length to the user's buffer, then unlock
+ // and free the MDL describing the user's buffer.
+ //
+
+ if( NT_SUCCESS(status2) ) {
+
+ status2 = TdiCopyBufferToMdl(
+ &SourceAddressLength,
+ 0,
+ sizeof(SourceAddressLength),
+ addressLength,
+ 0,
+ &addressBytesCopied
+ );
+
+ }
+
+ MmUnlockPages( addressLength );
+ IoFreeMdl( addressLength );
+
+ //
+ // If either of the above TdiCopyBufferToMdl calls failed,
+ // then use its status code as the completion code.
+ //
+
+ if( !NT_SUCCESS(status2) ) {
+
+ status = status2;
+
+ }
+
+ } else {
+
+ ASSERT( addressLength == NULL );
+
+ }
+
+ //
+ // Set up the IRP for completion.
+ //
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = bytesCopied;
+
+ return status;
+
+} // AfdSetupReceiveDatagramIrp
+